2016-03-23 18 views
0

Betrachten Sie den folgenden Code-Schnipsel:PHP preg_match_all passt nicht alles

$example = "DELIM1test1DELIM2test2DELIM1test3DELIM2test4"; // and so on 

preg_match_all('/DELIM1(.*?)DELIM2(.*?)/', $example, $matches); 

$matches Array wird:

array:3 [ 
    0 => array:2 [ 
    0 => "DELIM1test1DELIM2" 
    1 => "DELIM1test3DELIM2" 
    ] 
    1 => array:2 [ 
    0 => "test1" 
    1 => "test3" 
    ] 
    2 => array:2 [ 
    0 => "" 
    1 => "" 
    ] 
] 

Wie Sie sehen können, scheitert es test2 und test4 zu bekommen. Irgendein Grund, warum das passiert und was könnte eine mögliche Lösung sein? Vielen Dank.

Antwort

3

.*? ist nicht gierig; Wenn Sie danach keine Einschränkung mehr haben, wird es mit dem Minimum übereinstimmen: Null Zeichen. Sie benötigen eine Einschränkung, um mehr als nur trivial zu sein. Zum Beispiel:

/DELIM1(.*?)DELIM2(.*?)(?=DELIM1|$)/ 
2

Faule Subpattern am Ende des Geplapper Spiels entweder 0 (*?) oder 1 (+?) Zeichen, weil sie so wenig wie möglich entsprechen.

Sie können immer noch faul Matching verwenden und ein Look-Ahead-hängen, die eine DELIM1 benötigen nach dem Wert oder dem Ende der Zeichenfolge erscheinen:

/DELIM1(.*?)DELIM2(.*?)(?=$|DELIM1)/ 

demo See. Es ist sehr eng in Bezug auf die Leistung mit einem tempered greedy token (DELIM1(.*?)DELIM2((?:(?!DELIM1).)*) - demo).

Allerdings ist der beste Ansatz ist es entrollen:

DELIM1(.*?)DELIM2([^D]*(?:D(?!ELIM1)[^D]*)*) 

another demo

3

preg_split Siehe wäre besser:

$example = "DELIM1test1DELIM2test2DELIM1test3DELIM2test4"; // and so on 
$keywords = preg_split("/DELIM1|DELIM2/", $example,0,PREG_SPLIT_NO_EMPTY); 
print_r($keywords); 

Ausgang:

Array 
(
    [0] => test1 
    [1] => test2 
    [2] => test3 
    [3] => test4 
) 

DM o: http://ideone.com/s5nC0k

0

können Sie diesen negativen Look-Ahead-regex verwenden:

preg_match_all('/DELIM1((?:(?!DELIM1|DELIM2).)*)DELIM2((?:(?!DELIM1|DELIM2).)*)/', 
       $example, $matches); 

(?:(?!DELIM1|DELIM2).)* passen auf 0 oder mehr von beliebigen Zeichen, das nicht DELIM1 oder DELIM2 bei der nächsten Position hat.

Ausgang:

print_r($matches); 

    Array 
    (
     [0] => Array 
      (
       [0] => DELIM1test1DELIM2test2 
       [1] => DELIM1test3DELIM2test4 
      ) 

     [1] => Array 
      (
       [0] => test1 
       [1] => test3 
      ) 

     [2] => Array 
      (
       [0] => test2 
       [1] => test4 
      )   
    ) 
2

Diese Werte sind außerhalb Ihrer Anker, so dass sie nicht angepasst bekommen. z.B. (Mit einigen zusätzlichen Leerzeichen)

str: DELIM1 test1 DELIM2   test2 DELIM1 test3 DELIM2  test4 
pat: DELIM1 (.*?) DELIM2 (.*?)   DELIM1 (.*?) DELIM2 (.*?) 
      match #1        match #2 

(.*?) ist ein nicht-gierige Spiel, und kann/wird eine 0-Zeichenfolge entsprechen. Da die Grenze zwischen M2 und te eine 0-Länge-Zeichenfolge ist, stimmt dieses unsichtbare Zeichen der Länge 0 überein und das Muster endet dort.