2016-03-23 3 views
0

Рассмотрим следующий фрагмент кода:PHP preg_match_all не соответствует всем

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

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

$matches массив становится:

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

Как вы можете видеть, это не удается получить test2 и test4. Любая причина, почему это происходит и что может быть возможным решением? Спасибо.

ответ

3

.*? не является жадным; если у вас нет ограничений после него, он будет соответствовать минимально необходимым: нулевые символы. После этого вам потребуется ограничение, чтобы заставить его соответствовать более чем тривиально. Например:

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

Ленивых подмасок в конце матча скороговорки либо 0 (*?) или 1 (+?) символов, потому что они соответствуют как можно.

Вы можете использовать ленивое согласование, и добавить предпросмотр, который потребует DELIM1 появляться после значения или в конце строки:

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

См demo. Он очень близок с точки зрения производительности с tempered greedy token (DELIM1(.*?)DELIM2((?:(?!DELIM1).)*) - demo).

Однако, лучший подход раскатать его:

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

См another demo

3

preg_split будет лучше:

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

выход:

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

дем О: http://ideone.com/s5nC0k

0

Вы можете использовать это негативное опережение регулярное выражение:

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

(?:(?!DELIM1|DELIM2).)* будет соответствовать 0 или более любым символам, которые не имеют DELIM1 или DELIM2 на следующей позиции.

Выход:

print_r($matches); 

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

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

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

Эти значения находятся вне вашего якоря, так что они не будут согласованы. например (С некоторыми дополнительными пробелами)

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

(.*?) является нежадным матч, и может/будет соответствовать строке 0 длины. Так как граница между M2 и te является строкой длиной 0 строк, символ невидимой нулевой длины совпадает и шаблон заканчивается там.

Смежные вопросы