Регулярное выражение не выполняется, когда шаблон включает знак доллара ($)


Я сталкиваюсь с небольшой проблемой, когда дело доходит до сопоставления подшаблонов, которые включают знак доллара. Например, рассмотрим следующий фрагмент текста:

Regular Price: $20.50       Final Price: $15.20
Regular Price: $18.99       Final Price: $2.25
Regular Price: $11.22       Final Price: $33.44
Regular Price: $55.66       Final Price: $77.88

Я пытался сопоставить обычные/окончательные наборы цен со следующим регулярным выражением, но это просто не работало (никаких совпадений вообще):
preg_match_all("/Regular Price: \$(\d+\.\d{2}).*Final Price: \$(\d+\.\d{2})/U", $data, $matches);

Я избежал знака доллара, так что же получается?

 17
Author: Mr. Llama, 2011-03-19

2 answers

Внутри строки в двойных кавычках обратная косая черта рассматривается как escape-символ для $. Обратная косая черта удаляется синтаксическим анализатором PHP еще до того, как функция preg_match_all ее увидит:

$r = "/Regular Price: \$(\d+\.\d{2}).*Final Price: \$(\d+\.\d{2})/U";
var_dump($r);

Вывод (идеон):

"/Regular Price: $(\d+\.\d{2}).*Final Price: $(\d+\.\d{2})/U"
                 ^                           ^
              the backslashes are no longer there

Чтобы исправить это, используйте строку в одинарных кавычках вместо строки в двойных кавычках:

preg_match_all('/Regular Price: \$(\d+\.\d{2}).*Final Price: \$(\d+\.\d{2})/U',
               $data,
               $matches);

Посмотрите, как он работает онлайн: ideone

 35
Author: Mark Byers, 2011-03-18 21:39:04

Я знаю, что этот вопрос немного устарел, но я нашел это, пытаясь найти ответ на ту же проблему. Я увидел, что он находится на вершине рейтинга поисковых систем, поэтому решил, что было бы неплохо объяснить простую альтернативу и почему это происходит со строками в двойных кавычках ( " )

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

Мое решение состояло в том, чтобы "дважды избежать" знака доллара. В вашем примере это должно выглядеть примерно так:

"/Regular Price: \\\$(\d+\.\d{2}).*Final Price: \\\$(\d+\.\d{2})/U";

Обратите внимание, что знак доллара теперь содержит 3 косых черты \\\.

В принципе, у нас есть два "уровня" интерпретации: PHP и выражение регулярного выражения. Что происходит, так это то, что с одной косой чертой PHP интерпретирует ее как буквальный символ вместо модификатора переменной, поэтому он съедает косую черту, интерпретирует строку, как описано в ответ, а затем отправляет его в регулярное выражение, которое интерпретируется как взгляд назад.

"дважды избегая" знака доллара, PHP интерпретирует \\\$ как \\ и \$ соответственно. Мы экранируем \ из первого набора символов и экранируем $ из второго набора, в результате чего получаем только \$ после интерпретации PHP. Это отправит литеральную строку

"/Regular Price: \$(\d+\.\d{2}).*Final Price: \$(\d+\.\d{2})/U";

Для регулярного выражения, которое будет интерпретировать \$ как символьный литерал $, который будет соответствовать $ вместо того, чтобы действовать как взгляд назад, так как он ускользнул. Здесь важно понимать двойные уровни интерпретации, поскольку и PHP, и регулярное выражение имеют свои собственные правила интерпретации, и для правильного экранирования символов может потребоваться до 4 косых черт.

Строки в одинарных кавычках не имеют этой проблемы, так как для использования переменной $foo в строке нам пришлось бы написать

'Hello '. $foo .'!';

Вместо

"Hello $foo!";

Как мы можем в двойных строках. В отличие от строк в двойных кавычках, строки в одинарных кавычках не могут интерпретируйте переменные внутри строки как переменные (если они не добавлены, как в примере выше), вместо этого интерпретируйте их как обычный текст. Поскольку нам больше не нужно экранировать переменную, мы можем обойтись просто

'/Regular Price: \$(\d+\.\d{2}).*Final Price: \$(\d+\.\d{2})/U'

, который отправит \$ в регулярное выражение, такое же, как и с \\\$ в строке с двойными кавычками.

Все зависит от личных предпочтений, какой стиль вы используете или какой проще для шаблона.

TL;DR: Используйте \$ для строк в одинарных кавычках, таких как '/Hello \$bob/is' и \\\$ для строк в двойных кавычках, таких как "/Hello \\\$bob/is".

 6
Author: shmeeps, 2011-10-21 21:22:10