匹配报价内容

时间:2010-08-24 21:54:49

标签: regex

我正在尝试从字符串中删除引号。例如:

"hello", how 'are "you" today'

返回

hello, how are "you" today

我正在使用php preg_replace。

我现在有几个解决方案:

(\'|")(.*)\1

问题是它匹配中间的所有字符(包括引号),所以结果($ 2)是

hello", how 'are "you today'

反向引用不能用于字符类,所以我不能使用像

这样的东西
(\'|")([^\1\r\n]*)\1

与中间的第一个反向引用不匹配。

第二个解决方案:

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

问题是,这包括后引用中的引号,因此根本不执行任何操作。结果($ 1):

"hello", how 'are "you" today'

3 个答案:

答案 0 :(得分:3)

而不是:

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

简单地写一下:

\'([^\']*)\'|"([^"]*)"
  \______/    \_____/
     1           2

现在其中一个组将匹配引用的内容。

在大多数情况下,当替换字符串中引用了无法匹配的组时,空字符串将被替换,因此您可以简单地替换为$1$2,其中一个将成功捕获(取决于替代)和另一个将替换空字符串。

这是一个PHP实现(as seen on ideone.com):

$text = <<<EOT
"hello", how 'are "you" today'
EOT;

print preg_replace(
  '/\'([^\']*)\'|"([^"]*)"/',
  '$1$2',
  $text
);
# hello, how are "you" today 

仔细看看

我们使用12作为引号(为清晰起见)。还将添加空格(为清晰起见)。

之前,作为您的第二个解决方案,您有这种模式:

(  1[^1]*1  |  2[^2]*2  )
\_______________________/
   capture whole thing
   content and quotes

正如您正确指出的,这正确匹配一对引号(假设您无法转义引号),但它不会捕获内容部分。

这可能不是一个问题,取决于上下文(例如,您可以简单地从开头和结尾修剪一个字符以获取内容),但同时,解决问题并不难:只需捕获分别从两种可能性中得出内容。

1([^1]*)1  |  2([^2]*)2
 \_____/       \_____/
 capture contents from
each alternate separately

现在,组1或组2将捕获内容,具体取决于匹配的替代项。作为“奖励”,您可以检查使用了哪个引用,即如果组1成功,则使用1


附录

[…]character class。像[aeiou]这样的东西匹配任何一个小写元音。 [^…]否定的字符类。 [^aeiou]除了小写元音之外的任何内容匹配。

(…)用于grouping(pattern)是一个捕获组,并创建一个反向引用。 (?:pattern)无法捕获。

参考

答案 1 :(得分:2)

关于:

  

反向引用不能用于字符类,所以我不能使用像

这样的东西
(\'|")([^\1\r\n]*)\1
(\'|")(((?!(\1|\r|\n)).)*)\1

(其中(?!...)...)的负面预测应该有用。

我不知道这是否解决了你的主要问题,但它确实解决了“匹配一个字符,如果它不匹配背板”部分。

编辑:

错过了一个括号,已修复。

答案 2 :(得分:0)

您无法使用正则表达式执行此操作。这需要内部状态来跟踪(除其他外)

  • 是否遇到某种类型的先前引用
  • “外部”报价水平是否为当前水平
  • 是否有一组“内部”引号,如果是,那么这组引号在字符串中开始的地方

这需要语法感知解析器才能正确执行。正则表达式引擎不保持状态,因为它是一个有限状态自动机,它只对当前输入进行操作,而不管以前的情况。

这与您无法可靠地匹配嵌套括号或XML元素集的原因相同。