Sancho: regexp - mehrere Wörter in beliebiger Reihenfolge

Hallo Experten,

Gibt es einen von mir bisher übersehenen Regexp-modifier bzw. -switch mit dem ich nach _mehreren_ Wörtern suchen kann, die in _beliebiger_ Reihenfolge vorkommen können, wobei aber jedes der Wörter wenigstens einmal vorhanden sein muss?

Beispiel:

Text:
  'hans war gestern irgendwie komisch'

gesucht werden:
  'gestern'
  'komisch'
  'hans'

'matchender' (aber sehr umständlicher) regulärer Ausdruck
(und noch ohne Berücksichtigung der Wortgrenzen):

$re = '/(gestern.*komisch.*hans)|(gestern.*hans.*komisch)|(komisch.*gestern.*hans)| (etc.) /'

---

Hintergrund der Frage ist eine MySQL-Tabelle mit _mehreren_ Textfeldern.
Die Suche soll für jeden einzelnen Datensatz genau dann als erfolgreich gelten, wenn der gesuchte reguläre Ausdruck auf alle seine Textfelder _zusammen_ zutrifft.
Dadurch erhöht sich die Verknüpfungsdimension noch zusätzlich; und ich denke mal, dass in so einem Fall eine WHERE-clause der Form:

"WHERE CONCAT_WS(' ', feld1, feld2, feld3) REGEXP '$re'"

die resourcenschonendste Variante ist, denn andernfalls wäre folgendes notwendig:

"WHERE CONCAT_WS(' ', feld1, feld2, feld3) REGEXP '$re1'  [ $re1 = '/(^|\W+)gestern($|\W+)/' ]
   AND CONCAT_WS(' ', feld1, feld2, feld3) REGEXP '$re2'    [ $re2 = '/(^|\W+)komisch($|\W+)/' ]
   AND CONCAT_WS(' ', feld1, feld2, feld3) REGEXP '$re3'"   [ $re3 = '/(^|\W+)hans($|\W+)/' ]

(Also mehrere CONCAT_WS- und REGEXP-Aufrufe. Ohne REGEXP komme ich auch in diesem Fall nicht aus wegen der Wortgrenzen. Ich kann nämlich nicht

"WHERE CONCAT_WS(' ', feld1, feld2, feld3) LIKE '%hans%'
  ..."

verwenden, da ja einerseits nicht 'hans' aus '...hansa...' oder '...hanse...' -
 andereseits aber 'hans' aus
 '... hans ...'
 '... hans,...'
 '... hans!...'
 etc.
 sehr wohl gefunden werden soll.)

---

Ich hoffe mein Problem einigermaßen deutlich beschrieben zu haben...

Also nochmal die Frage: Wie läßt sich ein regulären Ausdruck konstruieren, der auf mehrere Wörter in beliebiger Reihenfolge zutrifft? Geht das nur über die Aneinanderreihung aller möglichen Kombinationen - oder gibt es eine andere Möglichkeit?

Grüße,

Sancho

  1. hi,

    Hintergrund der Frage ist eine MySQL-Tabelle mit _mehreren_ Textfeldern.
    Die Suche soll für jeden einzelnen Datensatz genau dann als erfolgreich gelten, wenn der gesuchte reguläre Ausdruck auf alle seine Textfelder _zusammen_ zutrifft.
    Dadurch erhöht sich die Verknüpfungsdimension noch zusätzlich; und ich denke mal, dass in so einem Fall eine WHERE-clause der Form:

    "WHERE CONCAT_WS(' ', feld1, feld2, feld3) REGEXP '$re'"

    die resourcenschonendste Variante ist

    na ja, ich würde mir noch mal überlegen, ob nicht eine FULLTEXT SEARCH über alle spalten performanter sein könnte ...

    gruß,
    wahsaga

    --
    "Look, that's why there's rules, understand? So that you _think_ before you break 'em."
    1. Hallo wahsaga,

      na ja, ich würde mir noch mal überlegen, ob nicht eine FULLTEXT SEARCH über alle spalten performanter sein könnte ...

      gruß,
      wahsaga

      Stimmt, aber das FULLTEXT SEARCH-Ergebnis informiert mich, soviel ich weiß, nicht genau über das exakte Zutreffen der Suchbedingung sondern ordnet die Ergebnisse nur nach einer 'Relevanz', in deren Interpretation ich ich erst einarbeiten müsste. Hast Du da ev. einen Link parat?

      thx,

      Sancho

    2. Nochmal hallo wahsaga,

      Ahem... sorry für die vielleicht etwas konsternierende Frage nach einem 'paraten' Link...
      (Klingt ein wenig nach 'Link bei Fuß'.)

      Die MySQL-Doku selbst beispielsweise ist recht dürftig, was die Erläuterungen zu FULL TEXT SEARCH betrifft (siehe http://dev.mysql.com/doc/mysql/de/fulltext-search.html).

      Daher nochmal; bist Du vielleicht schonmal irgendwo über einen Link gestolpert, wo diese Funktion, die noch mit einigen TODOs behaftet zu sein scheint, näher erläutert wird?

      Würde mir wirklich weiterhelfen...

      (Denn den von mir gesuchten regulären Ausdruck gibt es wahrscheinlich nicht. Schade.)

      Gruß, Sancho

  2. Hallo Sancho,

    Beispiel:

    Text:
      'hans war gestern irgendwie komisch'

    gesucht werden:
      'gestern'
      'komisch'
      'hans'

    Dazu braucht man doch gar keine Regulären Audrücke, das geht mit
    strpos():

    $text = 'hans war gestern irgendwie komisch';
    $match = array('gestern','komisch','hans');

    function match($string,$needle) {
     foreach ($needle as $value) {
      if (!strpos($string,$value)) return false;
     }
     return true;
    }

    Gruß
    Alexander Brock

    --
    SelfCode: ie:{ fl:( br:> va:) ls:[ fo:) rl:( n4:? ss:| de:> js:( ch:| sh:( mo:} zu:}
    http://againsttcpa.com
    1. Hallo Alexander,

      $text = 'hans war gestern irgendwie komisch';
      $match = array('gestern','komisch','hans');

      function match($string,$needle) {
      foreach ($needle as $value) {
        if (!strpos($string,$value)) return false;
      }
      return true;
      }

      ...das bekomme ich aber nicht in die SQL-Abfrage...

      Trotzdem Danke.

      Gruß, Sancho

  3. Hallo Sancho,

    $re = '/(gestern.*komisch.*hans)|(gestern.*hans.*komisch)|(komisch.*gestern.*hans)| (etc.) /'

    Wieso nicht einfach ((gestern)|(komisch)|(hans))*

    Gruß,

    Dieter

    1. Hallo Dieter,

      Wieso nicht einfach ((gestern)|(komisch)|(hans))*

      Weil das nur ein ODER- und keine UND-Verknüpfung ist.

      Gruß, Sancho

  4. Hi,

    Gibt es einen von mir bisher übersehenen Regexp-modifier bzw. -switch mit dem ich nach _mehreren_ Wörtern suchen kann, die in _beliebiger_ Reihenfolge vorkommen können, wobei aber jedes der Wörter wenigstens einmal vorhanden sein muss?

    Hintergrund der Frage ist eine MySQL-Tabelle mit _mehreren_ Textfeldern.

    Muß es ein Regex sein?
    Sonst

    WHERE spalte LIKE '%hans%' AND spalte LIKE '%gestern%' AND spalte LIKE '%komisch%'

    cu,
    Andreas

    --
    Warum nennt sich Andreas hier MudGuard?
    Schreinerei Waechter
    Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
    1. Hi Mudguard,

      Muß es ein Regex sein?
      Sonst

      WHERE spalte LIKE '%hans%' AND spalte LIKE '%gestern%' AND spalte LIKE '%komisch%'

      Äh - ja (wie ausgeführt). Weil ich eben gern die Option zur Suche nach Einzelwörtern einbauen würde. Und wie gesagt; Dein Vorschlag liefert mir auch die nicht gesuchten 'hanse-kogge' 'hängestern'. (Zweites Beispiel ist zugegebenermaßen ewtas 'gesucht'.)
      Ich hätte damit also das Problem nur auf die Auswertung des Query-Ergebnisses 'verschoben'.

      Wobei sich, da hast Du schon recht, die Anzahl der regex-Aufrufe dadurch natürlich reduzieren läßt;

      aber ich wage zu bezweifeln, dass

      30 mal mysql:LIKE   [bei 10 Zeilen mit 3 gesuchten Wörtern]

      und dann ggf.

      3 mal PHP:preg_match() [auf 3 Ergebnisse]

      performanter ist als

      10 mal mysql:REGEX  [bei besagten 10 Zeilen]

      Aber wie gesagt; mein Denkfehler scheint in der Suche nach einem regulären Ausdruck mit UND-Verknüpfung für Wörter zu liegen. Das scheint tatsächlich nur über die Aneinaderreihung aller Kombinationen zu gehen; und dann hat es spätestens ab 4 Wörtern wohl keinen Zweck mehr.

      cu2,
      Sancho.

      1. use Mosche;

        WHERE spalte LIKE '%hans%' AND spalte LIKE '%gestern%' AND spalte LIKE '%komisch%'

        Äh - ja (wie ausgeführt). Weil ich eben gern die Option zur Suche nach Einzelwörtern einbauen würde. Und wie gesagt; Dein Vorschlag liefert mir auch die nicht gesuchten 'hanse-kogge' 'hängestern'. (Zweites Beispiel ist zugegebenermaßen ewtas 'gesucht'.)

        Warum? Auf das Suchergebnis trifft "spalte LIKE '%gestern%'" ja nicht zu, und die Bedingungen sind (wie gefordert) mit UND-verknüpft.

        Oder steh ich auf dem sprichwörtlichen Schlauch?
        use Tschoe qw(Matti);

        --
        Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
        Webapplikationen in C++ entwickeln