18

如何编写一个匹配可以包含引号的模式的正则表达式,但如果确实如此,则必须在开头和结尾有匹配的引号?

"?(pattern)"?

将不起作用,因为它将允许以引号开头但不以引号结尾的模式。

"(pattern)"|(pattern)

会起作用,但会重复。有没有更好的方法可以在不重复模式的情况下做到这一点?

4

4 回答 4

25

您可以通过使用反向引用条件来获得解决方案而无需重复:

/^(")?(pattern)(?(1)\1|)$/

火柴:

  • 图案
  • “图案”

不匹配:

  • “图案
  • 图案”

然而,这种模式有些复杂。它首先查找可选引用,如果找到,则将其放入反向引用 1。然后它会搜索您的模式。然后它使用条件语法说“如果再次找到反向引用 1,则匹配它,否则不匹配”。整个模式是锚定的(这意味着它需要单独出现在一行上),这样不匹配的引号就不会被捕获(否则patterninpattern"会匹配)。

请注意,对条件的支持因引擎而异,更冗长但重复的表达式将得到更广泛的支持(并且可能更容易理解)。


更新:这个正则表达式的一个更简单的版本是/^(")?(pattern)\1$/,它不需要条件。当我最初测试这个时,我使用的测试仪给了我一个假阴性,这导致我打折扣(哎呀!)。

为了后代和兴趣,我将保留有条件的解决方案,但这是一个更简单的版本,更有可能在更广泛的引擎中工作(反向引用是此处使用的唯一可能不受支持的功能)。

于 2010-08-25T18:23:52.910 回答
2

这也很简单:(".+"|.+). 确保第一个匹配带引号,第二个不带引号。

于 2020-04-15T20:07:03.193 回答
0

根据您使用的语言,您应该能够使用反向引用。像这样,说:

(["'])(pattern)\1|^(pattern)$

这样,您要求要么没有引号,要么两端都使用相同的引号。

于 2010-08-25T18:22:35.423 回答
0

这应该适用于递归正则表达式(需要更长的时间才能正确)。同时:在Perl中,您可以构建一个自我修改的正则表达式。我将把它作为一个学术例子;-)

my @stuff = ( '"pattern"', 'pattern', 'pattern"', '"pattern'  );

foreach (@stuff) {
   print "$_ OK\n" if /^
                        (")?
                        \w+
                        (??{defined $1 ? '"' : ''})
                       $
                      /x
}

结果:

"pattern" OK
pattern OK
于 2010-08-25T18:33:07.253 回答