匹配允许转义的字符串并不困难。 看这里: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字符有什么关系呢?没有它可以工作吗?
答案 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).)
挖出。这就是为什么这部分必须是第一个。