我希望使用.NET正则表达式找到不在双引号内的每个单词。这是一些示例文本:
Hello world I want to get all of these words as a match "but not these ones...
because they're inside a string. And maybe I'll \"escape\" the quotes too." Also,
these words should match. Now we're outside of the string. And I can't escape
quotes; \"this still shouldn't be matched."
所以我想要匹配:
Hello, world, I, want, to, get, all, of, these, words, as, a, match, Also,
these, words, should, match, Now, we, re, outside, of, the, string, And, I,
can, t, escape, quotes
这是否可以使用.NET regex外部堆栈和断言?我已经走到了这一步:
(?<=(?(rstack)|(?!))(?<-rstack>").*?(?<rstack>").*?)\w+... same thing for fstack
'当然,它不起作用。
答案 0 :(得分:2)
我认为,不是匹配引号外的单词,而是匹配引号内的单词,并用''替换它们。
在某种程度上,我建议您查看this question和@ RicardoNolde的回答:
(?>(?(STR)(?(ESC).(?<-ESC>)|\\(?<ESC>))|(?!))|(?(STR)"(?<-STR>)|"(?<STR>))|(?(STR).|(?!)))+
(请参阅他的问题,以获得比我能做的更好的解释,因为我不熟悉.NET引擎)。
这匹配引号内的所有单词。如果你删除它们(即替换为''),然后将结果字符串与@"\b(\w+)\b"
匹配,那么你就是对的。
然而除非您的字符串中包含,否则您将遇到问题
\"
与对应的"
相似)"This is a quote that contains another "quote", tricky!"
可以在引号内包含"This is a quote that contains another "
和", tricky!"
。(之前的正则表达式似乎适用于\"this still shouldn't be matched"
的示例,但如果将其更改为"this still shouldn't be matched\" but this should. "hi"
,则会遇到问题,因为内部\"
被视为逃脱报价而不是平衡货币对的一部分。)
话虽如此,如果 你的文字符合我上面提到的那三条规则,你可以用普通的正则表达式做你想做的事情(尽管我觉得既然你使用的是.NET,你也可以这么做利用其堆栈功能):
(?<!")\b[a-zA-Z]+\b(?=(?>((\\"|[^"])*)"(?>(\\"|[^"])*)")*(\\"|[^"])*$)
这意味着“匹配任何单词后跟偶数个未转义的引号。” 逻辑是,由于引号已配对,如果您不在一组引号内,则会有偶数(未转义)引号。
在行动here中查看它((?>...)
是为了避免正则表达式引擎执行不必要的反向跟踪,以便提高性能。
(注意:我将您不匹配的引号\"this still shouldn't be matched"
更改为"this still shouldn't be matched"
,以便输入符合上述三条规则。)
另请注意,您不能说“匹配任何单词后跟偶数引号”(包括转义的引号),因为您将遇到嵌套引号匹配内的单词问题。例如,Hello world "this is a quote \"containing another quote\" end quote" goodbye
将错误地使内部another quote
与正则表达式匹配,因为字符串中仍有偶数引号。
你真的需要所有引用对都是格式正确/匹配的和嵌套引号要转义才能使任何类型的正则表达式工作,.NET引擎或不
我建议使用@ RicardoNolde在其他问题(上面链接的)中的答案来删除所有引用的文字,然后匹配所有剩余的单词。
答案 1 :(得分:1)
此表达式使用平衡组返回所需的单词。匹配表达式后,引号内的单词可以作为m.Groups["word"].Captures.OfType<Capture>.Select(c=>c.Value)
访问。通过在模式中包含可选的断言,如果引号不平衡,匹配可能会失败;如果从表达式中删除,则忽略无关的引号。
以下是包含模式并打印所需输出的驱动程序。
string input = @"Hello world I want to get all of these words as a match ""but not these ones... because they're inside a string. And maybe I'll \""escape\"" the quotes too."" Also, these words should match. Now we're outside of the string. And I can't escape quotes; \""this still shouldn't be matched.""";
string pattern = @"(?>
^(?:
#capture word only if not inside a quotation
(?(quote)\w+|(?<word>\w+))
(?:
([^\w""]*|$)
(?(quote)
#if within a quote, close unless escaped
(?:(?<=\\)\""|(?<-quote>(?<!\\)\""))
|
#if not within a quote, open quote
(?<quote>\"")
)?
)*
)*
)$
(?(quote)(?!)) # will fail to match if extra quotes
# if line removed, will ignore extra quote";
RegexOptions options = RegexOptions.IgnorePatternWhitespace;
Match m = Regex.Match(input, pattern, options);
if (!m.Success) Console.WriteLine("Failed");
else
foreach (
var word in m.Groups["word"]
.Captures
.OfType<Capture>()
.Select(a => a.Value))
Console.WriteLine(word);