2011-03-18 67 views
16

当涉及匹配涉及美元符号的子模式时,我遇到了一些问题。例如,考虑下列文本块:当模式涉及美元符号时,正则表达式失败

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

尝试用美元符号\\\转义。推断问题美元符号与PHP使用$做一些工作的事实之间的关系可能没有问题。 (我也使用$做工作,它只是看起来合乎逻辑)。 – 2011-03-18 21:31:06

+3

你试过单引号而不逃避$? – palindrom 2011-03-18 21:31:07

回答

32

在双引号字符串中,反斜杠被视为$的转义字符。反斜杠由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

+0

...或者你也可以在'\ $'之前加一个\,结果相同。它不太漂亮,但它工作得很好。 – 2011-05-18 14:18:53

+0

我有同样的问题,现在感觉很蠢,谢谢! – jreed121 2011-10-20 16:00:33

+0

您的解决方案也适用于我使用Perl – Filype 2012-05-27 11:16:04

6

我知道这个问题有点老,但我在找到答案时发现了这个问题。我一看,原来是在搜索引擎排名的顶部,所以我想这将是很好解释的简单替代,为什么出现这种情况有双引号中的字符串(")

正则表达式我用的是含有大量的单引用其中的字符('),所以我不太愿意与他们包装表达,因为我不想逃避所有这些。

我的解决方案是“双重逃避”美元符号。在你的榜样,它应该类似于东西

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

需要注意的是美元符号包含现在\\\ 3条斜线。

基本上,我们有两个“层次”的解释,即PHP和正则表达式的解释。发生的事情是,使用一个斜杠,PHP将其解释为文字字符而不是变量修饰符,因此它会吃掉斜线,按照Mark的答案解释字符串,然后将其发送给正则表达式,后者将解释为后退。

通过“双重转义”美元符号,PHP将\\\$分别解释为\\\$。我们从第一组字符中跳出了\,并且从第二组中跳出$,导致PHP解释后只有\$。这将发送文本字符串

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

于正则表达式,这将解释\$作为字符文字$,这将匹配$,而不是背后充当一看,因为它是逃脱。在这里实现双层解释非常重要,因为PHP和正则表达式都有自己的解释规则,并且可能最多需要4个斜线才能正确转义字符。

单引号字符没有这个问题,因为在一个字符串中使用一个变量$foo,我们会写

'Hello '. $foo .'!'; 

,而不是

​​

喜欢,我们可以在双字符串。与双引号字符串不同,单引号字符串不能将字符串内部的变量解释为变量(除非像上面的例子中那样添加它们),而是将它们解释为纯文本。因为我们不必再逃避变量,我们可以逃脱只是

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

将发送\$到正则表达式,同样与\\\$在双引号字符串。

这是所有关于您使用哪种风格或哪种模式更容易的个人偏好的问题。

TL; DR:对单引号字符串使用\$,如'/Hello \$bob/is'\\\$,用于双引号字符串,如"/Hello \\\$bob/is"