guenni
Goto Top

Textdatei zeilenweise nach Suchbegriffen mit PHP und der Funktion strpos durchsuchen

Da schon mal der Wunsch auftaucht(e), eine Textdatei mittels Script (Batch, PHP, VBS etc. . . .) nach Begriffen zu durchsuchen, und dabei auch

Schwierigkeiten bestehen/bestanden, das Ergebnis von strpos auszuwerten, habe ich das jetzt mal hier wie folgt mit PHP und strpos umgesetzt.

Das Script nimmt zwei Parameter entgegen:

- Den Namen einer Textdatei (Auswahl mit Select-Box)
- Ein oder mehrere Suchbegriffe in einem Textfeld

Bei Aufruf wird ein im Script angegebenes Verzeichnis incl. Unterverzeichnisse ausgelesen. Die Dateitypen, die eingelesen werden sollen, können hier

durch Angabe der Dateiendung bestimmt werden. Die Datei, die durchsucht werden soll, kann dann mittels einer Select-Box ausgewählt werden (Ein bißchen Komfort).


Mittels zwei verschachtelten while-Schleifen wird die Textdatei nun durchsucht. Die äußere Schleife spricht dabei alle Zeilen einer Textdatei an,

die innere Schleife alle eingegebenen Suchbegriffe. Bei jedem Durchlauf der äußeren Schleife wird also geprüft, ob sich ein oder mehrere,

eingegebene Suchbegriffe in dieser Zeile befinden. Bei jedem Fund wird eine Zeile in einem Array abgelegt, die folgendes beinhaltet:

- den gefundenen Suchbegriff
- die Zeilennummer
- die Positionsnummer in der Zeile
- die Textzeile

Auch wenn nur das Fragment eines Wortes eingegeben wurde (z.B. genaue Schreibweise nicht bekannt), wird das Fragment innerhalb eines Wortes in einer

Zeile gefunden. Somit wird auch diese Zeile ausgegeben.

Einigen PHP-Funktionen steht das Zeichen @ voran. Dadurch werden funktionseigene Fehlermeldungen unterdrückt, die durch eigene Fehlerroutinen

ersetzt werden (können).

Das Array $limiter_arr enthält Zeichen wie "+, -, &, ;" usw., die normalerweise in Suchmaschinen benutzt werden, um Suchbegriffe zu trennen, zu verknüpfen oder

auszugrenzen etc.. Diese Zeichen werden im Script durch ein Komma ersetzt. Weitere Zeichen bitte selber ins Array schreiben.


Wäre natürlich reizvoll, das Script so zu optimieren, dass Suchbegriffe verknüpft bzw. ausgegrenzt werden können.


Suchergebnisse von strpos auswerten

Suchergebnisse sollten laut http://de2.php.net/manual/de/function.strpos.php mit dem Operator === ausgewertet werden.

Erklärung zu diesem Operator ==> http://de2.php.net/manual/de/language.operators.comparison.php


Und los geht's . . .

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
<html>
<head>
<title>Worte in Textdateien suchen</title>
</head>
<body>
<?php
/*
* Callbackfunktion mit Sortierkriterien, wird von usort benötigt
*/
function cmp($a, $b) {
 if ($a == $b) return 0;
 return ($a > $b)? 1 : -1;
}

/*
* Ein Array zur Aufnahme der Dateien
*/
$datei_arr=array();

/*
* Die Funktion liest ein Verzeichnis incl. Unterverzeichnisse aus.
* - $verzeichnis - das soll ausgelesen werden
* - &$arr - hier wird das Array (s.o.) übergeben. Das & ist eine Referenz auf die Variable,
* die hier durch direkt von der Funktion verändert wird.
*/
function dir_rekursiv($verzeichnis, &$arr){ 
/*
* Diese Dateitypen sollen eingelesen werden.
*/
 //$datei_typ_arr=array(0 => ".txt", 1 => ".php", 2 => ".htm", 3 => ".html"); 
 $datei_typ_arr=array(0 => ".txt");  
 $handle = @opendir($verzeichnis); 
 while ($datei =@readdir($handle)){ 
  if ($datei != "." && $datei != ".." ){   
   if (is_dir($verzeichnis.$datei)){ 
	  dir_rekursiv($verzeichnis.$datei."/", &$arr);  
	 }else{
	           /*
                               * strrchr(string $string, string $zeichen) gibt den Text nach dem letzten Vorkommen von $zeichen incl. $zeichen zurück.
                              */ 
                                $ext=strrchr($verzeichnis.$datei, ".");  
				 /*
				 * Wenn $ext in dem Dateitypen-Array vorkommt, Datei im Array ablegen.
				 */
				 if(in_array($ext, $datei_typ_arr)){
				  $arr=$verzeichnis.$datei;
				 }
				} 
   }
 } 
 @closedir($handle); 
}
/*
* Funktionsaufruf mit Verzeichnisangabe und Variable
*/
dir_rekursiv("/www/",$datei_arr);  

/*
* usort($array, Callback-Funktion) sortiert das Array. 
*/
usort ($datei_arr, 'cmp');  
?>
<!-- 
Ein Formular zur Eingabe. 
/-->
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">  
<p>Datei auswählen <select name="seldatei" title="Datei auswählen"></p>  
<option selected value=""> -- Datei auswählen -- </option>  
<?php
/*
* Dateinamen in der Selectbox ausgeben.
*/
foreach($datei_arr as $datei){
 echo "<option value=\"$datei\">$datei</option>";  
}
?>
<p></select></p>
<p>Suchbegriff(e) eingeben  <input type="text" name="suche" title="Geben sie einen oder mehrere Suchbegriff(e) ein"></p>  
<p><input type="submit" name="cmd" value="Suchen" title="Absenden"></p>  
</form>
<?php
/*
* Mit ini_set(PARAMETER) werden Fehler/Hinweise angezeigt.
*/
ini_set('error_reporting', E_ALL|E_STRICT);  
ini_set('display_errors', 'On');  
/*
* Parameter der Funktion:
* - ein oder mehrere Suchbegriffe
* - einen Dateinamen
*/
function findwort($wort,$textdatei){
/*
* Wenn kein Dateiname eingegeben ist,  Array mit Meldung füllen und beenden.
*/
 if(strlen(trim($textdatei))==0){
  $gef_zeilen_arr="Wählen sie einen Dateinamen";  
  return $gef_zeilen_arr;
 }
/*
* Wenn kein(e) Suchbegriff(e) vorhanden sind,  Array mit Meldung füllen und beenden.
*/
 if(strlen(trim($wort))==0){
  $gef_zeilen_arr="Geben sie einen oder mehrere Suchbegriff(e) ein";  
  return $gef_zeilen_arr;
 }
/*
* Falls ein User (aus Versehen oder "zum Testen") Trennzeichen eingibt wie +, - & usw., 
* werden diese durch ein Komma ersetzt. Die Liste $limiter_arr nach Bedarf erweitern.
*/
$limiter_arr=array(0 => "+", 1 => ";", 2 => "|", 3 => "&", 4 => " "/* Auch Leerzeichen durch Komma ersetzen */, 5 => "-");  
foreach($limiter_arr as $limiter){
 $wort=str_replace($limiter, ",", $wort);  
}
/*
* Suchbegriffe in $wort in einem Array ablegen.
* Enthält $wort nur ein Wort, hat das Array eben nur ein Element.
*/
$wort_arr=explode(",",trim($wort));  
/*
* Textdatei zeilenweise in ein Array einlesen.
* 160 ist die Zeilenlänge, erhöhen falls nötig.
*/
 $text_zeilen_arr=array();
 $f = @fopen($textdatei,"r");  
 /*
 * Wenn die Textdatei nicht geöffnet werden konnte (z.B. fehlende Rechte), Array mit Meldung füllen und beenden.
 */
 if(!$f){
  $gef_zeilen_arr="Datei: ".$textdatei;  
  $gef_zeilen_arr="Die Datei ".$textdatei." konnte nicht geöffnet werden";  
	return $gef_zeilen_arr;
 }
 while($zeile=@fgets($f,160)){
  $text_zeilen_arr=$zeile;
 }
 @fclose($f);
/*
* Zeilenweise das Array mit der Funktion strpos durchsuchen.
* strpos arbeitet case-sensitiv, deshalb werden mit strtolower
* alle Groß- in Kleinbuchstaben umgewandelt.
*/
 $gef_zeilen_arr=array();
 $gef_zeilen_arr="Datei: ".$textdatei;  
 $i=0;
 while($i<count($text_zeilen_arr)){//while 1
  $k=0;
	/*
	* In der inneren Schleife wird nun Wort für Wort geprüft, ob es in der Textzeile vorkommt.
	*/
	while($k<count($wort_arr)){//while 2
   $pos = @strpos(strtolower($text_zeilen_arr[$i]),strtolower($wort_arr[$k]));
	 /*
	 * Bitte den Operator "===" beachten. 
	 */
	 if($pos === false){
	  /*
	  * Wenn strpos das boolsche FALSE zurückgibt, passiert nichts.
		*/
		}else{
	 			 /*
				 * Ansonsten die Array-Zeile mit einer Meldung füllen.
				 * - ($i+1) - Da ein Array bei 0 beginnt, wird eine 1 aufaddiert, weil sonst die falsche Zeilennummer am Bildschirm ausgegeben würde.
				 * - ($pos+1) - Da strpos bei 0 anfängt zu zählen, wird eine 1 aufaddiert, weil sonst die falsche Positionsnummer am Bildschirm ausgegeben würde.
				 */
				 $gef_zeilen_arr="Der Suchbegriff ".$wort_arr[$k]." wurde in Zeile ".($i+1)." an Position ".($pos+1)." gefunden ==> ".$text_zeilen_arr[$i];  
				}
	 $k++;
	}//end while 2
  $i++;
 }//end while 1
 /*
 * Enthält das Array mind. 2 Elemente(den Dateinamen und eine oder mehr gefundene Textzeilen), so wird das Array zurückgegeben.
 * Ansonsten wird das Array mit einer Meldung gefüllt und zurückgegeben.
 */
 if(count($gef_zeilen_arr)>1){
  return $gef_zeilen_arr;
 }else{
 			 $gef_zeilen_arr="Der/die Suchbegriff(e) \"$wort\" wurde(n) nicht gefunden";  
			 return $gef_zeilen_arr;
			 }
}
/*
* Ist das Formular gesendet, gibt die Funktion ein Array zurück, deshalb mit foreach ausgeben.
*/
if(isset($_POST['suche'])){  
 $erg_arr=findwort($_POST['suche'],$_POST['seldatei']);  
 foreach($erg_arr as $erg){
  /*
	* Die gefundenen Textzeilen mit der Funktion htmlspecialchars ausgeben, falls die durchsuchte Textdatei
	* eine HTML/PHP - oder ähnliche Datei ist. 
	*/
  echo "<pre>".htmlspecialchars($erg)."</pre>";  
 }
}
?>
</body>
</html>


. . . und End' is'.


Gruß
Günni

Content-Key: 167073

Url: https://administrator.de/contentid/167073

Printed on: April 23, 2024 at 11:04 o'clock

Member: TsukiSan
TsukiSan May 28, 2011 at 15:20:21 (UTC)
Goto Top
Hallo Günni,

erst einmal vielen Dank, für deine Anleitung! Die wird sicher vielen von Nutzen sein, die mit PHP arbeiten.
deswegen auch ein hilfreich von mir
Aber, da du VBS und Co erwähnst: das läßt sich mit weniger Zeilen auch erfassen.
Ganz kurzes Bespiel:
SuchText = LCase("Im vbarchiv gibt es jede Menge Tipps und jede Menge Infos.")  
SuchZeichen = LCase("gibt")  
 
for i = 1 to len(Suchtext)
	temp = mid(Suchtext,i,Len(SuchZeichen))
	if temp = SuchZeichen then temp1 = temp1 & i & vbcrlf
next

msgbox temp1
Mich persönlich erschlägt der Code etwas. Aber eventuell liegt es daran, dass ich von PHP keine Ahnung habe.

Viele Grüße
Tsuki
Member: Guenni
Guenni May 29, 2011 at 07:52:40 (UTC)
Goto Top
Hi TsukiSan,

danke für dein Feedback. Auch in meinem Script ist der eigentliche Suchvorgang nur ein paar Zeilen lang,

nimmt man die Kommentarzeilen mal raus . . .

<?php
$i=0;
 while($i<count($text_zeilen_arr)){//while 1
  $k=0;
	/*
	* In der inneren Schleife wird nun Wort für Wort geprüft, ob es in der Textzeile vorkommt.
	*/
	while($k<count($wort_arr)){//while 2
   $pos = @strpos(strtolower($text_zeilen_arr[$i]),strtolower($wort_arr[$k]));
	 /*
	 * Bitte den Operator "===" beachten. 
	 */
	 if($pos === false){
	  /*
	  * Wenn strpos das boolsche FALSE zurückgibt, passiert nichts.
		*/
		}else{
	 			 /*
				 * Ansonsten die Array-Zeile mit einer Meldung füllen.
				 * - ($i+1) - Da ein Array bei 0 beginnt, wird eine 1 aufaddiert, weil sonst die falsche Zeilennummer am Bildschirm ausgegeben würde.
				 * - ($pos+1) - Da strpos bei 0 anfängt zu zählen, wird eine 1 aufaddiert, weil sonst die falsche Positionsnummer am Bildschirm ausgegeben würde.
				 */
				 $gef_zeilen_arr="Der Suchbegriff ".$wort_arr[$k]." wurde in Zeile ".($i+1)." an Position ".($pos+1)." gefunden ==> ".$text_zeilen_arr[$i];  
				}
	 $k++;
	}//end while 2
  $i++;
 }//end while 1
?>

Der Grund für die zwei while-Schleifen ist der, dass man mehrere Suchbegriffe eingeben kann, und jede Textzeile nach diesen Begriffen durchsucht wird. Die Suche nach

"vb tipp info" in der Zeile "Im vbarchiv gibt es jede Menge Tipps und jede Menge Infos." z.B. hätte dann zur Folge, dass diese Zeile zusammen mit einem der Suchbegriffe

dreimal ausgegeben wird. Das Script liest außerdem ein Verzeichnis samt Unterverzeichnisse aus, sortiert die Dateinamen und stellt diese in einer select-Box zur Auswahl dar,

damit man den Dateinamen nicht eintippen muß. Der Rest sind halt Fehlerbehandlung etc.. Ich wollte halt nicht nur die Funktion strpos erklären, das kann man selber hier

http://de2.php.net/manual/de/function.strpos.php nachlesen, sondern eine Anwendung vorstellen, die auch zur Inspiration dienen kann. Man könnte z.B. dieses Script so umschreiben,

dass die Seiten eines Projekts durchsucht werden, um dann, statt die gef. Zeilen auszugeben, z.B. eine Linkliste auf Projektseiten zu generieren.

Danke auch für dein "hilfreich".


Gruß, schönen Sonntag

Günni
Member: Guenni
Guenni Jun 05, 2011 at 17:14:52 (UTC)
Goto Top
Hallo!

Änderungen im Script.

Im Dateitypenarray die Dateiendungen mit Punkt angeben.

Zeile 31:

$datei_typ_arr=array(0 => ".txt", 1 => ".php", 2 => ".htm", 3 => ".html");


Statt strpos wird nun strrchr verwendet. strpos(string $string, -3) findet

so nur die letzten 3 Zeichen, bei der Endung html also nur tml.

ab Zeile 40:

/*
  • strrchr(string $string, string $zeichen) gibt den Text nach dem letzten Vorkommen von $zeichen incl. $zeichen zurück.
*/
$ext=strrchr($verzeichnis.$datei, ".");

Gruß
Günni