我正在尝试从字符串中删除引号。例如:
"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'
答案 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
我们使用1
和2
作为引号(为清晰起见)。还将添加空格(为清晰起见)。
之前,作为您的第二个解决方案,您有这种模式:
( 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元素集的原因相同。