嗯,Alan Moore 的回答很好,但我会对其进行一些修改以使其更紧凑。对于正则表达式编译器:
"([^"\\]*(\\.)*)*"
对比艾伦·摩尔的表情:
"[^"\\]*(\\.[^"\\]*)*"
解释和艾伦摩尔的解释很相似:
第一部分" 匹配一个引号。
第二部分[^"\\]* 匹配零个或多个除引号或反斜杠以外的任何字符。
最后一部分(\\.)* 匹配反斜杠及其后面的任何单个字符。注意*,表示该组是可选的。
所描述的部分以及最后的"(即"[^"\\]*(\\.)*")将匹配:“Some Text”和“Even more Text\”,但不会匹配:“Even more text about \”this文本\""。
为了使它成为可能,我们需要以下部分:[^"\\]*(\\.)* 被重复多次,直到出现未转义的引号(或者它到达字符串的末尾并且匹配尝试失败)。所以我用括号将那部分包裹起来并添加了一个星号。现在它匹配:“Some Text”、“Even more Text\””、“Even more text about \"this text\"”和“Hello\\”。
在 C# 代码中,它看起来像:
var r = new Regex("\"([^\"\\\\]*(\\\\.)*)*\"");
顺便说一句,两个主要部分的顺序:[^"\\]* 和 (\\.)* 无关紧要。你可以写:
"([^"\\]*(\\.)*)*"
或
"((\\.)*[^"\\]*)*"
结果是一样的。
现在我们需要解决另一个问题:\"foo\"-"bar"。当前表达式将匹配到"foo\"-",但我们希望将其匹配到"bar"。我不知道
为什么在引用的字符串之外会有转义的引号
但我们可以通过在开头添加以下部分来轻松实现它:(\G|[^\\])。它表示我们希望匹配从前一个匹配结束的点或除反斜杠之外的任何字符之后开始。为什么我们需要\G?这适用于以下情况,例如:"a""b"。
请注意,(\G|[^\\])"([^"\\]*(\\.)*)*" 与 \"foo\"-"bar" 中的 -"bar" 匹配。因此,要仅获取"bar",我们需要指定组并可选地为其命名,例如“MyGroup”。然后 C# 代码将如下所示:
[TestMethod]
public void RegExTest()
{
//Regex compiler: (?:\G|[^\\])(?<MyGroup>"(?:[^"\\]*(?:\.)*)*")
string pattern = "(?:\\G|[^\\\\])(?<MyGroup>\"(?:[^\"\\\\]*(?:\\\\.)*)*\")";
var r = new Regex(pattern, RegexOptions.IgnoreCase);
//Human readable form: "Some Text" and "Even more Text\"" "Even more text about \"this text\"" "Hello\\" \"foo\" - "bar" "a" "b" c "d"
string inputWithQuotedText = "\"Some Text\" and \"Even more Text\\\"\" \"Even more text about \\\"this text\\\"\" \"Hello\\\\\" \\\"foo\\\"-\"bar\" \"a\"\"b\"c\"d\"";
var quotedList = new List<string>();
for (Match m = r.Match(inputWithQuotedText); m.Success; m = m.NextMatch())
quotedList.Add(m.Groups["MyGroup"].Value);
Assert.AreEqual(8, quotedList.Count);
Assert.AreEqual("\"Some Text\"", quotedList[0]);
Assert.AreEqual("\"Even more Text\\\"\"", quotedList[1]);
Assert.AreEqual("\"Even more text about \\\"this text\\\"\"", quotedList[2]);
Assert.AreEqual("\"Hello\\\\\"", quotedList[3]);
Assert.AreEqual("\"bar\"", quotedList[4]);
Assert.AreEqual("\"a\"", quotedList[5]);
Assert.AreEqual("\"b\"", quotedList[6]);
Assert.AreEqual("\"d\"", quotedList[7]);
}