在匹配涉及美元符号的子模式时,我遇到了一些问题。例如,请考虑以下文本块:
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);
我逃过了美元符号,所以给出了什么?
答案 0 :(得分:37)
在双引号字符串中,反斜杠被视为$
的转义字符。即使在preg_match_all
函数看到它之前,PHP解析器也会删除反斜杠:
$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
答案 1 :(得分:6)
我知道这个问题有点旧,但我在试图找到同样问题的答案时发现了这个问题。我看到它处于搜索引擎排名的顶端,所以我认为解释一个简单的替代方案会很好,为什么会出现双引号字符串( " )
我使用的正则表达式中包含大量单引号字符( ' )
,所以我不太热衷于用它们包装表达式,因为我不想逃避所有这些。< / p>
我的解决方案是“双重逃脱”美元符号。在您的示例中,它应该看起来类似于
"/Regular Price: \\\$(\d+\.\d{2}).*Final Price: \\\$(\d+\.\d{2})/U";
请注意,美元符号现在包含3个斜杠\\\
。
基本上,我们有两个“级别”的解释,PHP和正则表达式。发生的事情是,使用一个斜杠,PHP将其解释为文字字符而不是变量修饰符,因此它吃掉斜杠,按Mark的答案中所述解释字符串,然后将其发送到regex,后者将其解释为后视。
通过“双重转义”美元符号,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'
会将\$
发送到regex,与双引号字符串中的\\\$
相同。
所有这些都取决于您使用哪种风格的个人偏好,或者哪种风格更容易。
TL; DR:对\$
等单引号字符串使用'/Hello \$bob/is'
,对\\\$
等双引号字符串使用"/Hello \\\$bob/is"
。