使用正则表达式将带引号的字符串与嵌入的非转义引号匹配

Posted

技术标签:

【中文标题】使用正则表达式将带引号的字符串与嵌入的非转义引号匹配【英文标题】:Using Regex to match quoted string with embedded, non-escaped quotes 【发布时间】:2011-12-04 02:05:19 【问题描述】:

我正在尝试将以下模式中的字符串与正则表达式匹配。

string text = "'Emma','The Last Leaf','Gulliver's travels'";
string pattern = @"'(.*?)',?";

foreach (Match match in Regex.Matches(text,pattern,RegexOptions.IgnoreCase))
 
    Console.WriteLine(match + " " + match.Index);
    Console.WriteLine(match.Groups[1].Captures[0]);
 

这正确匹配“Emma”和“The Last Leaf”,但第三个匹配是“Gulliver”。但理想的匹配是“格列佛游记”。如何为这样的模式构建正则表达式?

【问题讨论】:

更多的是语言问题:) 如果您在输入字符串中添加逗号,您可以去掉导致错误匹配的,? 中的?。您是否无法获得正确转义的输入字符串?如果这本书真的被命名为"Gulliver','s travels",你会怎么做? 您可以使用平衡分组 (blogs.msdn.com/b/bclteam/archive/2005/03/15/396452.aspx) 处理嵌套字符。但是,嵌套字符并不是最糟糕的问题。真正的问题是Gulliver's 中的撇号没有被转义。这确实使解析器的规则难以定义。 @Steve:我认为撇号是 OP 所说的,而这根本与嵌套无关。我从标题中删除了“嵌套”一词。 【参考方案1】:

由于, 是您的分隔符,您可以尝试像这样更改您的模式。它应该可以工作。

string pattern = @"'(.*?)'(?:,|$)"; 

它的工作方式是查找单引号,后跟逗号或行尾。

【讨论】:

+1 因为它“在这里工作”,但请参阅 bzlm 的(也许很傻 ;-) 反例:'Emma','The Last Leaf','Gulliver','s travels' - 请记住,正则表达式相对脆弱 i> 野兽。 @pst OP 的要求是匹配两个单引号之间的字符串部分,并且每个单引号仅用逗号分隔。据我了解, 是这里唯一的救援。否则,正如您所说,此任务需要复杂(或不可能)的正则表达式。将上述正则表达式应用于您提供的文本会给出预期的输出 Emma,The Last Leaf,Gulliver 和毫无意义的 s travels +1。只要您正在解析的字符串不涉及超出我们已经看到的逗号和撇号的奇怪组合,那么这就足够了。【参考方案2】:

我认为这可以将'(.*?)',|'(.*)' 用作正则表达式。

【讨论】:

用 LINQPad (linqpad.org) 试试 -- 是否 有效?如果格列佛的旅行是第一个呢? 我已经检查了 expresso(ultrapico.com) 两个版本(最后/开头的格列佛)似乎都有效 它可以工作,因为交替是有序的。它总是首先尝试'(.*?)',,并且匹配除了最后一个项目之外的所有项目,而不管嵌入的撇号如何。相当优雅,真的。 顺便说一下,如果你把它改成'(?<title>.*?)',|'(?<title>.*)',你可以通过Groups["title"]来检索想要的部分,而不必使用程序逻辑来确定是哪个组进行了匹配。 不知何故错过了 expresso 的建议。它是一个有用的小工具。谢谢esunar【参考方案3】:

你可以考虑使用向后看/向前看:

 "(?<=^'|',').*?(?='$|',')"

用 grep 测试

kent$  echo "'Emma','The Last Leaf','Gulliver's travels'"|grep -Po "(?<=^'|',').*?(?='$|',')"
Emma
The Last Leaf
Gulliver's travels

【讨论】:

【参考方案4】:

如果您有单引号分隔的字符串并且Gulliver's 包含一个未转义的单引号,则无法将其与字符串的末尾区分开来。你总是可以用逗号分隔它并从两边修剪's,但我不确定这是你想要的:

string text = "'Emma','The Last Leaf','Gulliver's travels'";

foreach(string s in text.split(new char[] ',')) 
    Console.WriteLine(s.Trim('\''));

【讨论】:

从技术上讲,它可以与字符串的结尾区分开来,因为引号后面没有逗号,或者是输入中的最后一个字符。 :) @bzlm:我想你有自己的答案:)

以上是关于使用正则表达式将带引号的字符串与嵌入的非转义引号匹配的主要内容,如果未能解决你的问题,请参考以下文章

Java Regex 用于将带引号的字符串与转义引号匹配

具有奇怪行为的正则表达式:将字符串与反向引用匹配以允许转义以及单引号和双引号

使用正则表达式转义单引号字符串中的所有双引号 [重复]

正则表达式 - 获取引号中的字符串忽略转义的引号和评论

使用正则表达式在 C# 中使用转义引号查找带引号的字符串

正则表达式在单引号内转义双引号