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);
Я избежал знака доллара, так что дает?
Ответы
Ответ 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"
.