Подтвердить что ты не робот

Regex не работает, когда шаблон включает знак доллара ($)

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

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);

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

4b9b3361

Ответ 1

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

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

Выход (ideone):

"/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

Ответ 2

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

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

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

"/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";

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

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

'Hello '. $foo .'!';

вместо

"Hello $foo!";

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

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

который отправит \$ в regex, то же, что и с \\\$ в строке двойной кавычки.

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

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