регулярное выражение, проблема с обратной ссылкой в ​​шаблоне с preg_match_all - PullRequest
2 голосов
/ 19 мая 2011

Интересно, в чем проблема с обратными ссылками здесь:

preg_match_all('/__\((\'|")([^\1]+)\1/', "__('match this') . 'not this'", $matches);

ожидается, что строка соответствует __ (''), но на самом деле возвращает:

match this') . 'not this

есть идеи?

Ответы [ 4 ]

6 голосов
/ 19 мая 2011

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

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

preg_match_all('/__\(([\'"])(?:(?!\1).)+\1\)/',
    "__('match this') . 'not this'", $matches);

Я также изменил ваше чередование - \'|" - на класс символов - [\'"] - потому что это намного эффективнее, и я избежал внешнегокруглые скобки, чтобы они соответствовали буквальным круглым скобкам.


РЕДАКТИРОВАТЬ: я думаю, мне нужно расширить это "более эффективное" замечание.Я взял пример , который использовал Фридл, чтобы продемонстрировать это, и протестировал его в RegexBuddy.

Применяется к целевому тексту abababdedfg,
^[a-g]+$ сообщает об успехе после трех шагов, в то время как
^(?:a|b|c|d|e|f|g)+$ делает 55 шагов.

И это для успешный матч.Когда я пробую abababdedfz,
^[a-g]+$ сообщает о сбое после 21 шага;
^(?:a|b|c|d|e|f|g)+$ делает 99 шагов.

В этом конкретном случае влияние на производительность настолько тривиально, что это не такдаже стоит упомянуть.Я просто говорю, что всякий раз, когда вы выбираете между классом персонажа и чередованием, которые совпадают с одними и теми же вещами, вы почти всегда должны использовать класс персонажа.Просто правило.

2 голосов
/ 19 мая 2011

Я удивлен, что оно не выдает сообщение об ошибке в скобках для дисбаланса.

 /
   __
   (
       (\'|")
       ([^\1]+)
       \1
 /

Это [^\1] не будет принимать содержимое буфера захвата 1 и помещать его в символ
учебный класс.Это то же самое, что и все символы, которые НЕ являются '1'.

Попробуйте это:

/__\(('|").*?\1\).*/

Вы можете добавить внутреннюю круглую скобку, чтобы просто захватить то, что междукавычки:
/__\(('|")(.*?)\1\).*/

Редактировать: Если внутренний разделитель недопустим, используйте регулярное выражение Qtax.
Поскольку, ('|").*?\1, даже если он не жадный, все равно будет соответствовать всем до конечного якоря,В этом случае __('all'this'will"match'), и лучше использовать ('[^']*'|"[^"]*) как

1 голос
/ 19 мая 2011

Вы можете использовать что-то вроде: /__\(("[^"]+"|'[^']+')\)/

0 голосов
/ 19 мая 2011

Сделайте свое регулярное выражение неприличным:

preg_match_all('/__((\'|")([^\1]+)\1/U', "__('match this') . 'not this'", $matches)
...