2016-11-11 7 views
0

Ich versuche, einen regulären Ausdruck zum Teilen einer Zeichenfolge zu erstellen, aber leider sind meine Anforderungen ein wenig komplexer als eine einfache Aufteilung, so dass ich zum Beispiel preg_split() in PHP nicht verwenden kann.Extraneous Empty Trailing Match

Also was ich tue, ist die Übereinstimmung meiner Begrenzer (oder vielmehr, Teil von ihnen) in einem Unterausdruck und alles davor in einem anderen Unterausdruck, und auch das Ende der Zeichenfolge als Trennzeichen dafür zu behandeln Zweck. Vor diesem Hintergrund kam ich mit dem Follow-up:

([^?;]*)(?|\?([0-9]*)|(;)|$) 

Wie Sie hoffentlich sehen können, das erste Untermuster für einen Textblock sieht ohne Fragezeichen der Semikolons. Danach habe ich ein Untermuster, das mit einem beliebigen Fragezeichen mit einer optionalen Zahl übereinstimmt (die gespeichert wird), entweder das oder ein Semikolon (das gespeichert wird) oder das Ende der Zeichenkette.

Das Problem ist, dass ich scheine ein Fremd, leer, Match gegen das Ende des String Fall zu bekommen, etwa so:

$sql = 'CALL foo(?0, ?1, ?2, ?3)'; 
preg_match_all('/([^?;]*)(?|\?([0-9]*)|(;)|$)/', $sql, $matches); 
print_r($matches); 

Ausgabe erzeugt, die wie folgt aussieht:

Array 
(
    [0] => Array 
     (
      [0] => CALL insert_host(?0 
      [1] => , ?1 
      [2] => , ?2 
      [3] => , ?3 
      [4] =>) 
      [5] => 
     ) 

    [1] => Array 
     (
      [0] => CALL insert_host(
      [1] => , 
      [2] => , 
      [3] => , 
      [4] =>) 
      [5] => 
     ) 

    [2] => Array 
     (
      [0] => 0 
      [1] => 1 
      [2] => 2 
      [3] => 3 
      [4] => 
      [5] => 
     ) 

) 

Hinweis das leere Spiel unter $matches[0][5]; Ich hätte erwartet, dass das Ende des String-Cases nach dem Anpassen der Klammer erfüllt wird, was zu keinem weiteren Matching führt, aber es ist weiter gegangen, um ein weiteres Match zu produzieren, und ich kann nicht herausfinden, warum.

Also meine Frage ist; Warum wird hier ein zusätzliches Spiel erstellt und wie verhindere ich es?

HINWEIS: Ich habe bereits in Erwägung gezogen, dass das Ende des String Case mindestens ein Zeichen davor haben muss, aber das ist nicht gut, da ich tatsächlich ein leeres Ergebnis haben möchte, wenn ein Wildcard auf der Seite ist string, weil ich versuche, das Verhalten einer Split-Funktion zu emulieren. Zum Beispiel, wenn die Eingabe SELECT ? wäre, würde ich erwarten, dass SELECT ? plus eine leere Zeichenfolge übereinstimmen. Die Idee hier ist, dass, sobald ich alle abgeglichenen Semikolons bearbeitet habe, ich einfach implode('?', $matches[1]) machen kann, um die Aussage mit numerischen Wildcards zu reproduzieren.

Antwort

0

Ich glaube, ich habe vielleicht eine Alternative zu meinem speziellen Fall herausgefunden, die das Problem lösen wird; was ich habe, ist der Ausdruck um so gekippt gemacht, dass ein Begrenzer ersten oder angepasst ist, in Ermangelung eines solchen, der Beginn der Zeichenfolge, etwa so:

(?|\?([0-9]*)|(;)|^)([^?;]*) 

Das die erwarteten Ergebnisse in allen Fällen erzeugt:

preg_match_all('/(?|\?([0-9]*)|(;)|^)([^?;]*)/', 'CALL foo(?3, ?2, ?1, ?0)', $matches); 
print_r($matches); 

Produziert:

Array 
(
    [0] => Array 
     (
      [0] => CALL foo(
      [1] => ?3, 
      [2] => ?2, 
      [3] => ?1, 
      [4] => ?0) 
     ) 
    [1] => Array 
     (
      [0] => 
      [1] => 3 
      [2] => 2 
      [3] => 1 
      [4] => 0 
     ) 

    [2] => Array 
     (
      [0] => CALL foo(
      [1] => , 
      [2] => , 
      [3] => , 
      [4] =>) 
     ) 
) 

While:

preg_match_all('/(?|\?([0-9]*)|(;)|^)([^?;]*)/', 'SELECT ?', $matches); 
print_r($matches); 

Produziert:

Array 
(
    [0] => Array 
     (
      [0] => SELECT 
      [1] => ? 
     ) 
    [1] => Array 
     (
      [0] => 
      [1] => 
     ) 
    [2] => Array 
     (
      [0] => SELECT 
      [1] => 
     ) 
) 

Allerdings funktioniert dies nur, weil ich weiß, dass die Eingabe wird nie ein Trennzeichen als erstes Zeichen umfassen; Wenn ich einen anbiete, stößt es auf das gleiche Problem, so dass ich nicht sicher bin, ob ich es als echte Lösung bezeichnen soll oder nicht.

Ich bin auch immer noch interessiert zu wissen, warum mein ursprünglicher Ausdruck eine zusätzliche Übereinstimmung bekam, da ich gieriges Matching erwarten würde, dass es unmöglich war, denn sobald das Ende der Zeichenfolge übereinstimmt, sollte nichts mehr übrig sein finden.