具有奇怪行为的RegEx:将String与后引用匹配以允许转义以及单引号和双引号

时间:2010-10-25 08:57:52

标签: regex string escaping

匹配允许转义的字符串并不困难。 看这里:http://ad.hominem.org/log/2005/05/quoted_strings.php。 为了简单起见,我选择了这种方法,其中一个字符串被分成两个“原子”:一个字符“不是引号或反斜杠”或反斜杠后跟任何字符。

"(([^"\\]|\\.)*)"

现在显而易见的改进是允许不同的引号并使用反向引用。

(["'])((\\.|[^\1\\])*?)\1

还可以正确解释多个反斜杠。

现在到了部分,它变得奇怪:我必须解析一些这样的变量(注意第一个变量值中缺少反斜杠):

test = 'foo'bar'
var = 'lol'
int = 7

所以我写了一个表达。我发现它的下一部分没有按预期工作(只有上面的表达式的差别是附加的“([\ r \ n] +)”):

(["'])((\\.|[^\1\\])*?)\1([\r\n]+)

尽管缺少反斜杠,'foo'bar'仍然匹配。我使用了gskinner的RegExr(在线工具),但PHP(PCRE)具有相同的行为。

要解决此问题,您可以通过用'替换反向引用来对引号进行硬编码。然后它按预期工作。 这是否意味着反向引用确实在这种情况下不起作用?这与linebreak字符有什么关系呢?没有它可以工作吗?

1 个答案:

答案 0 :(得分:2)

您不能在字符类中使用反向引用;在这种情况下,\1将被解释为八进制1(至少在一些正则表达式引擎中,我不知道这是否普遍正确)。

所以请尝试以下方法:

(["'])(?:\\.|(?!\1).)*\1(?:[\r\n]+)

或者,作为一个冗长的正则表达式:

(["'])       # match a quote
(?:          # either match...
 \\.         # an escaped character
 |           # or
 (?!\1).     # any character except the previously matched quote
)*           # any number of times
\1           # then match the previously matched quote again
(?:[\r\n]+)  # plus one or more linebreak characters.

编辑:删除了一些不必要的括号,并将一些更改为非捕获括号。

你的正则表达式坚持在匹配的字符串后找到至少一个回车 - 为什么?如果它是您文件的最后一行怎么办?或者如果字符串后面有注释或空格?你可能应该完全放弃那部分。

另请注意,您无需使*延迟使用 - 正则表达式无法跨越未转义的引号字符 - 并且您不必在第二个中检查反斜杠交替的一部分,因为所有反斜杠都已被交替的第一部分(?:\\.|(?!\1).)挖出。这就是为什么这部分必须是第一个。