Intelligentes Search-Script (Klammern)

Hallo,

ich hätte da mal eine Frage betreffend PHP und Dateien.

Ich würde gerne ein Script schreiben, dass mir nach einem Suchbegriff (Input-Feld) in einer Datei sucht…
Das ganze sollte etwas komplexer bzw. intelligenter sein - nämlich es soll mit and, or, not und Klammern umgehen können.

Das and, or, not ist ja kein Problem…
Nur wie löse ich das ganze jetzt mit Klammern?

Ich gehe die Sache folgendermaßen an…
Searchstring kommt über das Input Feld, wird anhang von and or oder not mit explode zerlegt und jenachdem dann danach gesucht…

Nur wich mache ich jetzt das mit Klammern da muss ich nach dem exploden bzw. ausschneiden (…Inhalt…).

Ein Beispiel:

(rot and gelb) or grün
rot and (gelb or grün)
2 Dinge die anhang ihrer Klammern komplett unterschiedlich sind.

Die Datei wird Zeilenweise eingelesen und Zeile für Zeile ausgegeben, wurde in einer Zeile etwas gefunden, wird die Zeile ausgegeben…

WIE KANN ICH DAS AM BESTEN LÖSEN?

Lg
Christof

Das einfachste ist du baust das in einen Regulären Ausdruck um.

Wie die Dinger funktionieren erfährst du etwa hier: regular-expressions.info/tutorial.html

[quote=“michi7x7”]Das einfachste ist du baust das in einen Regulären Ausdruck um.

Wie die Dinger funktionieren erfährst du etwa hier: regular-expressions.info/tutorial.html[/quote]

Ehrlich gesagt weis ich nicht wie ich diese Dinger einsetzen soll in meinem Fall?!
Ich meine valid-eMail Überprüfungen usw. sind kein Problem, nur wie hilft mir das bei meinem Problem (kleiner Denkanstoß :smiley:).

Bzw. helfen mir die dann auch bei meinem and, or, not problem oder nur bei den Klammern?
Jetzt löse ich das mit den and usw. mit einigen umständlichen if’s…

Bzw. kann es ja auch der Fall sein dass entweder gar keine Klammern verwendet wurden oder kein Verknüpfungsoperator…
…also wenn nur nach einem einzelnen Wort gesucht wurde…

also wie müsste ich das jetzt angehen dass ich z.B.:
(rot and grün) or blau
richtig in 3 Wörter zerlege und auf and/or achte…

Hab mir gedacht:

  1. Schritt: Klammern entfernen und inhalte in Array speichern
  2. Schritt: nach den 3 Schlüsselwörtern (and, not, or) suchen und richtig abarbeiten…

lg

ich würde aus

einfach

machen, das kannst du dann bequem per RegEx verwenden :wink:

Du musst es aber nicht so machen, ist nur eine Idee :wink:

zB ginge es auch mit eval() und strpos:

zuerst Zeile/Datei filtern: $rot, $blau, $gruen setzen
und dann if(eval("return (($rot and $green) or $blau);")) echo "Jap!";

möglichkeiten gibts viele :wink:

Naja das mit den Farben war nur ein Bsp.
Das mit den regex muss ich mir mal genauer anschauen…

Aber speziell gehts um eine syslog Datei und da kann natürlich nach ziemlich vielen Dingen gesucht werden…

IPs, Protokolle usw…

also ich weis nicht nach was gesucht wird…

Da solltest du dir überlegen, ob nicht etwa das schreiben in eine DB sinnvoller ist :wink:

Du kannst dem User auch anbieten direkt einen RegEx einzutragen, was unter Umständen sinnvoll sein könnte.
Egal wie du es machst, das hier wäre die Lösung wenn du den RegEx hast:

function find($string, $line)
{
   global $results, $filter;

   if(preg_match($filter, $string))
      $results[] = $line;
}

$lines =file("datei.log");
$results = array();
$filter = "/test/i";   //Regex bauen

array_walk($lines, 'find');

print_r($results); //Enthält Array mit Zeilenindexen

Danke vielmals, werd mir das mal anschauen…

Naja würde ich das machen würde ich es in eine DB schreiben…
…aber ist nicht mein Server…

Die Funktion wird bei mir nicht viel helfen…

Denn ich weis nicht wann er and eingibt, als drittes Wort oder zweites oder gar nicht…
Gibt es den irgendeine Möglichkeit eines “explodes” woch ich nicht einen delimiter abgebe sondern zwei und das zwischen den zwei ‘Trennern’ wird dann in ein Array gespeichert?
Oder einen Work Arround dafür?

Reguläre Ausdrücke bieten dir natürlich mehr Möglichkeiten, als ein simples explode.
(Ich meine in der Hinsicht wie Michis Vorschlag, sie direkt zum Suchen zu benutzen - sondern um damit erst mal einen “Parser” zu schreiben, der die Eingabe analysiert und in “Code” zum Durchführen einer Suche umsetzt.)

Wie gesagt ich stehe irgendwie auf der Leitung.

Ich weis nicht wie ich das in regex formen kann…

Hiermal ein par Bsp. Eingaben:

Hab mal die Dinge auf die man aufpassen muss fett gemacht…
Ich weis nicht wirklich weiter.
Bzw. habe ich jetzt schon Probleme wenn ich

durchgehe das es mir die Ausgabe bzw. überhaupt mal die keywords beachtet…

Das Problem beim RegEx ist das AND, denn ein RegEx soll auf einen String passen

Eine Suche in dem Stiel wäre kein Problem: abc xyz (123 OR 345) end

$search = "abc xyz (123 OR 345) end";

$preg = "!$search!i";
$preg = preg_replace("°([a-z0-9]+)\sOR\s([a-z0-9]+)°i", "$1|$2", $preg);
$preg = preg_replace("°\s+°i", "(.*)", $preg);

Nur wenn die Eingabe nur ein Wort ist zB xyz, funktioniert das ja nicht, weil er sich Klammern und ein OR erwartet.

Und ich kann den User ja nicht zwingen nach mehreren Parametern zu suchen bzw. ist das ja nicht immer gewünscht…

Wie müsste den eine regex aussehen die ein AND, OR und NOT optional beinhalten kann und auch von der Anzahl her unbegrenzt ist.

Also dass die regex genau so:

xyz or abc or tzu or lololo or klkl
fasf and adf or asdflk
abc or wer
kasf or adf and adfk or adf
zuio or asdf or asdf
asdfkj and asdf and adfn
asdf

wenn man die Klammern jetzt mal ausenvor lässt?
Wäre das realisierbar oder andere Möglichkeiten besser?

lg

Hallo,

ich werde die Sache jetzt mal etwas anders angehen…

...
$searchstring = trim($_POST['suchstring']);
$andteile = spliti("and", $searchstring);
...

Jetzt habe ich bei folgender Eingabe diese Array:

Eingabe: xyz and abc and dsf OR yxy or tztz and lale

Array (
[0] => xyz
[1] => abc
[2] => dsf OR yxy or tztz
[3] => lale
)

Wie gehe ich jetzt am besten weiter vor damit ich am Ende folgende Bedingung bekomme:
if (eregi($andteile[0], $file[$i]) && eregi($andteile[1], $file[$i])…)

natürlich müsste die if Abfrage dynamisch sein sie enthält entweder 1 eregi() oder X eregi() getrennt durch AND/OR.

Mein Problem ist jetzt wie baue ich die if Abfrage dynamisch auf?#
Bzw. vorher muss ich noch die OR herausbringen…

lg

Das Problem ist, dass du pro Suchanfrage dann 5 Suchabfragen hast, was natürlich langsamer sein kann.
Außerdem ist AND sowiso wegfällig, da die Wörter ja schon mit AND verbunden sind. Wofür du OR und Klammern brauchst, ist mir sowiso noch nicht ganz schlüssig :ps:

Warscheinlich kannst du es mit so einem Array-Aufbau lösen:

Array (
   [0] => "abc",
   [1] => "def",
   [2] => array(
       [0] => "123",
       [1] => "456",
       [type] => "OR",
       ),
   [3] => "xyz",
   [type] => "AND",
   );

Das ganze könntest du dann rekursiv durchgehen:

function check($on, $search_array)
{
   $type = $search_array['type'];
   $len = size($search_array) -1;
   for($i=0; $i<$len; $i++)
   {
       if(is_array($search_array[$i))
          $found = check($on, $search_array[$i])
       else
           $found = (strpos($on, $search_array[$i]) !== FALSE);
       if($found && $type == "OR") return true;
       if(!$found && $type == "AND") return false;
    }
    return ($type == "AND");
}

Ist aber, wie gesagt, langsamer als ein RegEx

So…jetzt habe ich nochmals alles über den Haufen geworfen und nochmals begonnen, nur diesmal scheint es fast vollendet.

Ein OR benötige ich wenn ich nur einen der zwei Sachen finden will.

Also wenn zB in einer Zeile rot vorkommt und in der anderen blau (rot OR blau) dann gibt er mir beide Zeilen aus…

Meine derzeitige, etwas einfacher gelöste Methode:

*) 5 input Felder und daneben Radio-Buttons.
*) In das input-Feld wird klarerweise der Suchbegriff eingegeben
*) Bei den Radio-Buttons kann man dann den Operator anklicken (and, or, not)

Ablauf:

  1. Input Felder mittels Schleife ausgeben
  2. 3 Arrays anlegen und befüllen ($filledkriterium, $searchstrings, $operator)
    …$filledkriterium = true/false -> jenachdem ob im input was eingegeben wurde
    …$searchstrings = Der Inhalt des input-Feldes
    …$operator = Das Value der Radio Buttons (and, or, not)
  3. ???

Ich durchsuche so meine Datei…

[code] $file = file($dateiname);

for($i=0; $i<count($file); $i++)
{
  if (eregi($searchstring, $file[$i]))
  {
	echo "$file[$i]<br />";
  }
}[/code]

Nur müsste diese Abfrage: if(eregi($searchstring, $file[$i])) jetzt dynamisch gestaltet sein…
$searchstring müsste mittels Schleife vom Array ausgelesen werden, $i kommt eh aus der Schleife.
Und jetzt das Schwierigere nach der eregi() Methode muss evtl. ein OPERATOR kommen und danach nochmals ein eregi() usw…

Kann dann zB so aussehen:

	  if (eregi($searchstring[1], $file[$i]) AND $searchstring[2], $file[$i]) OR $searchstring[3], $file[$i]))

Wie bekomme ich das hin?

Lg

Ich hab dir oben eine Lösung geschrieben. Außerdem ist eregi für Reguläre Ausdrücke, verwende lieber strpos($str, $search) !== FALSE

Danke schonmal für die großartige Hilfe!

[quote=“michi7x7”]Warscheinlich kannst du es mit so einem Array-Aufbau lösen:

Array (
   [0] => "abc",
   [1] => "def",
   [2] => array(
       [0] => "123",
       [1] => "456",
       [type] => "OR",
       ),
   [3] => "xyz",
   [type] => "AND",
   );

[/quote]
Gut das Array so auf zu bauen sollte kein Problem darstellen.

[quote=“michi7x7”]
Das ganze könntest du dann rekursiv durchgehen:

function check($on, $search_array) { $type = $search_array['type']; //Array Typ ermitteln $len = size($search_array) -1; //Arraygröße ermitteln for($i=0; $i<$len; $i++) { if(is_array($search_array[$i)) //Wenn das aktuelle Array-Element ein Array ist?! $found = check($on, $search_array[$i]) //ab hier durchblicke ich nicht mehr ganz :S else $found = (strpos($on, $search_array[$i]) !== FALSE); if($found && $type == "OR") return true; if(!$found && $type == "AND") return false; } return ($type == "AND"); } [/quote]
Dem Parameter $search_array übergebe ich klarerweise das zu durchsuchende Array, nur was übergebe ich dem Parameter $on?

Und wie muss ich dann weiter vorgehen?
Oder ist hier die Suche in der Datei schon integriert? - Ich durchblicke den Code nicht so recht…
Hab ich aber eh in im Code als Kommentar dazugeschrieben…

Lg

Irgendwie will das nicht so recht hinhauen…

[code]
for($i = 1; $i <= $anzahl_kriterien; $i++)
{
if(isset($_POST[“kriterium”.$i]) && $_POST[“kriterium”.$i] != “”)
{
$actoperator = $_POST[“operator”.$i];
$actkriterium = trim($_POST[“kriterium”.$i]);
$nextkriterium = trim($_POST[“kriterium”.$i+1]);

                    if($actoperator == "and")
                    {
                            $searchstrings[$i] = $actkriterium;
                            $searchstrings[$i+1] = $nextkriterium;
                            $searchstrings[type] = "AND";
                    }
                    elseif($actoperator == "or")
                    {
                            $searchsrings[$i] = array($actkriterium, $nextkriterium);
                            $searchstring[type] = "OR";
                    }
            }
    }[/code]

Das Array wird nicht richtig aufgebaut.
Außerdem blick ich bei der Funktion oberhalb noch immer nicht durch und wo gehört die dann aufgerufen?

Der Parameter $on ist der String auf dem die Suche ausgeführt wird.

Aufrufen kannst du es so:

$file = file("datei.log");

foreach($file as $i => $line)
   if(check($line, $search_array))
      echo "Treffer in Zeile ".($i+1);

Das Erstellen des Array geht auch wieder rekursiv:

$search_string = "abc def (xyz OR zyx) 123";
$search_array = do_array($search_string);

function do_array($string)
{
  if(!is_array($string))
    $string = explode(" ", $string);
  $array = array();
  $type = "AND";

  for($i=0; $i<count($string); $i++)
  {
    if($string[$i][0] == "(") //Begine Klammer
    {
      $temp = array();
      $temp[] = substr($string[$i], 1);
      for($j = $i+1; $j < count($string) && substr($string[$j], -1) != ")"; $j++)
        $temp[] = $string[$j];
      $temp[] = substr($string[$j], 0, -1);
      $array[] = do_array($temp);
      $i = $j; //Die Werte in der Klammer sind schon abgearbeitet
    } else {
      if($string[$i] == "OR")
        $type = "OR";
      else
        $array[] = $string[$i];
    }
  }
  $array['type'] = $type;
  return $array;
}

Oder so in etwa, diese Funktion unterstützt keine verschachtelten Klammern und ist sonst auch noch Ausbaufähig. Außerdem langsam :wink:

Danke funkt super!