Cheatah: Regulärer Ausdruck gesucht

Hi,

speziell für die Auswertung von Suchmaschinen-Querystrings suche ich einen RegExp, der mir den String in Einzelworte zerlegt. Bisher führe ich ein einfaches

@woerter = split(/ /,$query);

aus, wobei ich vorher noch Doublequotes und Boole'sche Operatoren (and, or, not) mit s/x//g; entferne. Das hat aber den Nachteil, daß z.B. 'ich suche "das hier"' in vier einzelne Wörter übersetzt wird anstatt in 'ich', 'suche' und 'das hier'.

Wie kann ich den split-Befehl umwandeln, damit er einen Querystring suchmaschinenkonform aufteilt, und zwar auch wenn mehrere Male Wörter eingequotet werden (z.B. '"ich suche" AND "das hier"')? Boole entferne ich auch weiterhin vorher, das soll kein Problem darstellen. Aber die Quotes...

Hilfe... *wimmer* :-)

Cheatah

  1. Hi,

    nun haengt Deine frage schon anderthalb Tage hier einsam rum und niemand erbarmt sich Deines Problems. *g*

    Naja, ich weiss leider auch keine so richtige Loesung, sonst haette ich schon eher mal was dazu geschrieben. Ich denke mir das so ungefaehr:

    Vor dem split ersetze die fraglichen Leerzeichen durch irgendwas anderes moeglichst einzigartiges (hier ###):
    $query =~ s/("\S+)\s(\S+")/\1###\2/g;

    Probleme die ich erwarte: Klappt das mit \1 und \2 so wie ich mir das denke? Und vielleicht wird hier nur das erste und das letzte Anfuehrungszeichen gefunden, nicht wiederholt die zusammengehoerigen (Du weisst schon, das Problem zu dem ich mal gefragt hatte, warum die Loesung funktioniert (irgendwo in einer der neuesten Archivdateien)).

    Dann split wie bisher.

    @woerter = split(/ /,$query);

    Dann die ### zurueckverwandeln und dabei gleich die Quotes entfernen:
    for (@woerter) { $_ =~ s/"([^#]+)###(.+)"/\1 \2/g }

    (alles ungetestet, hoffentlich nicht _zu_ fehlerhaft)

    Boole entferne ich auch weiterhin vorher, das soll kein Problem darstellen. Aber die Quotes...

    Und dass Du mir dran denkst, die Boole nur dann zu entfernen, wenn sie nicht innerhalb von Quotes stehen...

    Calocybe

    1. Hi Calocybe,

      nun haengt Deine frage schon anderthalb Tage hier einsam rum und niemand erbarmt sich Deines Problems. *g*

      danke *aufbodenwerfundfüßeküss* Ich fühlte mich schon ganz verlassen... :-)))

      Vor dem split ersetze die fraglichen Leerzeichen durch irgendwas anderes moeglichst einzigartiges (hier ###):

      Gute Idee eigentlich!

      $query =~ s/("\S+)\s(\S+")/\1###\2/g;

      Wenn ich das richtig sehe, wird dies '"string parse"' ersetzen durch '"string###parse"', aber '"string to parse"' durch sich selbst... bzw. ignorieren, weil hier 3 Wörter stehen. Aber egal, verfolgen wir die Idee mal weiter:

      $query =~ s/(".*"?) /$1###/g;
      @woerter = split(/###/,$query);

      Allerdings sind jetzt Leerzeichen zwischen "normalen", ungequoteten Wörtern noch nicht drin... Wie wäre es mit:

      $query =~ s/("\S*?) (.*")/$1###$2/g;

      Müßte doch '"string mit noch irgend was" anderem' in erster Instanz durch '"string###mit noch irgend was" anderem' ersetzen? Im Zweifelsfall kann ich dann ein while ($query =~ /".* .*"/) dazusetzen, falls das durch /g noch nicht erledigt ist. Hiernach splitte ich dann auf / / und ersetze anschließend alle ### wieder durch Leerzeichen. Ginge das?

      Probleme die ich erwarte: Klappt das mit \1 und \2 so wie ich mir das denke?

      Keine Ahnung, ich benutze immer $1 und $2, damit sollte es jedenfalls gehen!

      Und vielleicht wird hier nur das erste und das letzte Anfuehrungszeichen gefunden, nicht wiederholt die zusammengehoerigen (Du weisst schon, das Problem zu dem ich mal gefragt hatte, warum die Loesung funktioniert (irgendwo in einer der neuesten Archivdateien)).

      Ich habe jetzt halbwegs willkürlich *g* Fragezeichen dazugesetzt, in der Hoffnung daß es das bringt...

      Dann die ### zurueckverwandeln und dabei gleich die Quotes entfernen:
      for (@woerter) { $_ =~ s/"([^#]+)###(.+)"/\1 \2/g }

      Was macht denn ([^#]+)? So wie das für mich aussieht, bedeutet das "entweder Stringanfang oder Doppelkreuz, und davon mind. eines"...?
      Für mich klingt aber $_ =~ s/(###)+/ /g; logischer. Das müßte doch #-Tripel (und deren Ansammlungen, also ### (3) und ###### (6) und ######### (9), aber nicht #### (4)) durch ein Leerzeichen ersetzen, oder?

      (alles ungetestet, hoffentlich nicht _zu_ fehlerhaft)

      Solange wir uns gegenseitig zur Lösung schaukeln, sind Fehler okay... :-)

      Boole entferne ich auch weiterhin vorher, das soll kein Problem darstellen. Aber die Quotes...
      Und dass Du mir dran denkst, die Boole nur dann zu entfernen, wenn sie nicht innerhalb von Quotes stehen...

      Oh ja, danke für den Hinweis! Das habe ich glatt übersehen! Also etwa so:
      for (@woerter) {
         $_ =~ s/(###)+/ /g;
         $_ =~ s/^and$//i;
         $_ =~ s/^or$//i;
         $_ =~ s/^not$//i;
      }
      Oder?

      Danke für Deine Hilfe!

      Cheatah

      1. Hi,

        momentaner Stand der Dinge: Klappt nicht :-(

        Beste Ergebnisse erziele ich mit folgendem Code:

        $query =~ s/"(\S*?) (.*?)"/#$1&&$2#/g;
        @woerter = split(/ /,$query);
        foreach $foo (@woerter) {
           $foo =~ s/&&/ /g;
           $queries{$foo}++;
        }

        Ich habe noch (der Anschaulichkeit halber) Doublequotes in "#" ersetzt. Zeichen für "Space im String" ist nicht "###", sondern "&&", weil das garantiert nicht vorkommen kann (andere Teile der Programmierung).
        Hierbei werden Queries der Art '"zwei Wörter"' korrekt ausgewertet. Leider wird folgendes falsch übersetzt: ("/" für Trennung bei split)

        "drei ganze Wörter" -> #drei ganze / Wörter#
        "zwei Wörter" mit Anhang -> "zwei Wörter" / mit / Anhang (also "..." statt #...#)
        "zwei Wörter" "noch zwei" -> #zwei Wörter" #noch zwei" (keine Trennung!)
        "Wort" -> "Wort" (wieder "..." statt #...#)

        Jetzt kam mir folgender Gedanke: Kann man irgendwie erst den gefundenen Teilstring bearbeiten, also in etwa:

        $query =~ /"(.*?)"/   [$1 =~ s/ /&&/g]   /g;

        In eckigen Klammern ist also erst die Ersetzung... davor wird nur gesucht! Geht das irgendwie? So wären meine Probleme nämlich im nu gelöst... :-)

        Cheatah