0

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

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

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\"\\"

在这种情况下,第二个参数 end with \\"which 是允许嵌套字符串末尾的反斜杠的常规方式,不幸的是,正则表达式认为这是一个转义的引号,因为模式\"仍然存在于模式的末尾。

4

2 回答 2

4

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

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

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

请注意,交替的顺序很重要!

这样做的问题是,您不想转义不用于分隔字符串的引号。因此,另一种可能性是使用环视(因为反向引用不能在字符类中使用):

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

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

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

工作演示。

顺便说一句,这相当于:

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

但是在这里您必须再次按此顺序编写交替。

工作演示。

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

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

但是您说您正在寻找简短而优雅的东西;)(尽管最后一个可能更有效……但是您必须对其进行描述)。

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

$pattern = '/(?<!\\\\)(["\'])(?:\\\\\1|(?!\1).)+\1/';
于 2012-11-21T12:15:05.573 回答
1

试试这个正则表达式:

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

给定以下字符串:

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

它会匹配

"Hello"
'match 2'
"wqwqwqwq wwqwqqwqw"
"Hello \" World"
于 2012-11-21T12:17:21.630 回答