正则表达式匹配排除特定上下文

5
我试图查找字符串中带有单引号的词,但仅限于那些单引号不在括号内的情况。
例如字符串: something, 'foo', something ('bar') 所以对于给定的示例,我想匹配foo,但不是bar
在搜索正则表达式示例后,我能够匹配单引号中的内容(请参见下面的代码片段),但不确定如何排除先前描述的上下文中的匹配。
string line = "something, 'foo', something ('bar')";
Match name = Regex.Match(line, @"'([^']*)");
if (name.Success)
{
    string matchedName = name.Groups[1].Value;
    Console.WriteLine(matchedName);
}

括号是否直接包围单引号?即,对于“foo”,(text 'foo' text)是否匹配? - Richard
Regex101.com是一个非常好的网站,用于测试正则表达式,以确定它是否按照您的预期工作。 - Woot
2
@Woot:Regex101不支持.NET正则表达式。要测试.NET正则表达式,Ultrapico Expresso工具非常好。 - Wiktor Stribiżew
它们可能并不总是立即包围单引号。例如,如果要搜索的字符串是 ('a','b','c'),我不想匹配a、b或c。 - stratocaster_master
2个回答

3

我建议使用前瞻(lookahead)代替(在此处查看live),示例如下:

(?<!\()'([^']*)'(?!\))

或者使用C#:

string line = "something, 'foo', something ('bar')";
Match name = Regex.Match(line, @"(?<!\()'([^']*)'(?!\))");
if (name.Success)
{
    Console.WriteLine(name.Groups[1].Value);
}

2
使用交替组并匹配和捕获所需内容,仅匹配不需要的内容是获取所需内容最简单的方法:
\([^()]*\)|'([^']*)'

请参阅正则表达式演示详细信息
- \( - 匹配左括号( - [^()]* - 匹配0个或多个除了()之外的字符 - \) - 匹配右括号) - | - 或 - ' - 匹配单引号' - ([^']*) - 捕获组1,匹配0个或多个除了'之外的字符 - ' - 匹配单引号' 在C#中,使用.Groups[1].Value获取所需的值。请参阅在线演示
var str = "something, 'foo', something ('bar')";
var result = Regex.Matches(str, @"\([^()]*\)|'([^']*)'")
    .Cast<Match>()
    .Select(m => m.Groups[1].Value)
    .ToList();

另一种选择是由Thomas提出的,但由于它是.NET,您可以使用无限宽度回顾

(?<!\([^()]*)'([^']*)'(?![^()]*\))

请参考这个正则表达式演示

细节说明:

  • (?<!\([^()]*) - 负向零宽断言,如果在当前位置之前有(并且后面跟着0个或多个非()的字符,则匹配失败。
  • '([^']*)' - 匹配一个引号,将除单引号之外的0个或多个字符捕获到第1组,并匹配另一个单引号。
  • (?![^()]*\)) - 负向零宽断言,如果在当前位置之后有0个或多个非()的字符,后跟一个),则匹配失败。该断言在前一子模式中的最后一个'之后应用,以避免匹配'

由于您想要排除',因此与上面相同的代码适用。


我很感激你提供的深入解释,这有助于我理解你的方法。我正在尝试理解这两种解决方案之间的区别:无限宽度回顾提供了什么优势? - stratocaster_master
无限宽度的“向后查找”允许用*+量化的子模式。在需要的模式之前,可能会失败或需要出现更多的子模式比紧挨着的子模式更远的位置。 - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接