Preg Patterns,用于忽略转义字符

时间:2012-11-21 12:03:35

标签: php regex string matching expression

我想创建一个RegEx来查找以单引号或双引号开头和结尾的字符串。

例如,我可以匹配这样的情况:

String: "Hello World"
RegEx: /[\"\'][^\"\']+[\"\']/

但是,当引号出现在字符串本身时会出现问题:

String: "Hello" World"

我们知道上面的表达方式不起作用。

我希望能够做什么,它可以在字符串本身内进行转义,因为无论如何都需要功能:

String: "Hello\" World"

现在我可以想出一个长而复杂的表达式,在一个组中有各种模式,其中一个是:

RegEx: /[\"\'][^\"\']+(\\\"|\\\')+[^\"\']+[\"\']/

然而,对我而言似乎过分,我认为可能会有更短更优雅的解决方案。

预期语法:

run arg1 "arg1" "arg3 with \"" "\"arg4" "arg\"\"5"

正如您所看到的,引号实际上仅用于确保带空格的字符串被计为单个字符串。不要担心arg1,我应该能够匹配不带引号的参数。

我会使这更容易,参数只能使用双引号引用。所以我从这个问题的要求中引用了单引号。

我修改了Rui Jarimba的例子:

/(?<=")(\\")*([^"]+((\\(\"))*[^"])+)((\\"")|")/

现在这对大多数情况都很好,但是有一个最后的案例可以解决这个问题:

run -a "arg3 \" p2" "\"sa\"mple\"\\"

第二个参数以\\"结尾,在这种情况下是一种传统的方法,允许在嵌套字符串的末尾加一个反斜杠,不幸的是,正则表达式认为这是一个转义引用,因为模式\"仍然存在于模式的末尾。

2 个答案:

答案 0 :(得分:4)

首先,请使用'字符串来编写正则表达式。这可以为你节省很多时间。

然后我看到两种可能性。您尝试的问题是,它只允许在字符串中的一个位置连续转义引号。此外,这允许在开头和结尾使用不同的引号。您可以使用反向引用来解决这个问题。所以这将是a)稍微优雅和b)正确:

$pattern = '/(["\'])(\\"|\\\'|[^"\'])+\1/';

请注意,更改顺序很重要!

问题是,您不想转义不用于分隔字符串的引用。因此,另一种可能性是使用外观(因为后面的引用不能在字符类中使用):

$pattern = '/(["\'])(?:(?!\1).|(?<=\\\\)\1)+\1/';

请注意,始终需要四个连续的反斜杠来匹配单个文字反斜杠。这是因为在实际的字符串$pattern中它们最终为\\,然后正则表达式引擎“使用”第一个来逃避第二个。

如果起始引用,则匹配任意字符。或者,如果前一个字符是反斜杠,它将匹配起始引用。

Working demo.

这顺便说一下:

$pattern = '/(["\'])(?:\\\\\1|(?!\1).)+\1/';

但是在这里你再次按此顺序写下交替。

Working demo.

最后一点说明。您可以通过单独提供两个可能的字符串(单引号和双引号字符串)来避免反向引用:

$pattern = '/"(?:\\\\"|[^"])+"|\'(?:\\\\\'|[^\'])+\'/';

但是你说你正在寻找简短而优雅的东西;)(尽管,最后一个可能更有效......但你必须对此进行分析。)

请注意,我的所有正则表达式都会留下一个未考虑的案例:在引用字符串之外转义引号。即Hello \" World "Hello" World会给你" World"。您可以使用另一个负面的lookbehind来避免这种情况(例如,我提供了一个工作演示的第二个正则表达式;它对其他所有其他工作方式都一样):

$pattern = '/(?<!\\\\)(["\'])(?:\\\\\1|(?!\1).)+\1/';

答案 1 :(得分:1)

试试这个正则表达式:

['"]([^'"]+((\\(\"|'))*[^'"])+)['"]

给出以下字符串:

"Hello" World 'match 2' "wqwqwqwq wwqwqqwqw" no match here oopop "Hello \" World"

匹配

"Hello"
'match 2'
"wqwqwqwq wwqwqqwqw"
"Hello \" World"