【问题标题】:Regex matching excluding a specific context排除特定上下文的正则表达式匹配
【发布时间】:2026-02-11 16:35:01
【问题描述】:

我正在尝试在字符串中搜索单引号内的单词,但前提是这些单引号不在括号内。

示例字符串: something, 'foo', something ('bar')

所以对于给定的示例,我想匹配foo,而不是bar

搜索正则表达式示例后,我可以在单引号内进行匹配(参见下面的代码 sn-p),但不确定如何在前面描述的上下文中排除匹配项。

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

【问题讨论】:

  • 括号是否立即围绕单引号? IE。 (text 'foo' text) 应该匹配“foo”吗?
  • Regex101.com 是一个很棒的网站,用于测试正则表达式以确定它是否按您期望的方式运行。
  • @Woot:Regex101 不支持 .NET 正则表达式。测试 .NET 正则表达式,Ultrapico Expresso 工具非常好。
  • 它们可能并不总是立即围绕单引号。例如,如果要搜索的字符串是 `('a','b','c'),我不想匹配 a、b 或 c。

标签: c# regex


【解决方案1】:

我建议改用前瞻(参见live):

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

或者使用 C#:

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

【讨论】:

    【解决方案2】:

    获得所需内容的最简单方法是使用交替组并匹配和捕获您需要的内容,仅匹配您不需要的内容:

    \([^()]*\)|'([^']*)'
    

    regex demo

    详情

    • \( - 一个(
    • [^()]* - 除了 () 之外还有 0+ 个字符
    • \) - 一个)
    • | - 或
    • ' - 一个'
    • ([^']*) - 第 1 组捕获除 ' 之外的 0+ 个字符
    • ' - 单引号。

    在 C# 中,使用 .Groups[1].Value 获取您需要的值。见online demo

    var str = "something, 'foo', something ('bar')";
    var result = Regex.Matches(str, @"\([^()]*\)|'([^']*)'")
        .Cast<Match>()
        .Select(m => m.Groups[1].Value)
        .ToList();
    

    Thomas 提到的另一种选择,但由于它是 .NET,您可以使用 infinite-width lookbehind

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

    this regex demo

    详情

    • (?&lt;!\([^()]*) - 如果有 ( 后跟 0+ 个字符而不是 () ,则匹配失败后的否定查找
    • '([^']*)' - 一个引号,除单引号外的 0+ 个字符被捕获到第 1 组中,以及另一个单引号
    • (?![^()]*\)) - 如果除 () 之外还有 0+ 个字符,在前面的子模式中的 ' 之后紧跟 ),则否定前瞻将失败。

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

    【讨论】:

    • 我很欣赏深入的解释,帮助我理解你的方法。我试图了解这两种解决方案之间的区别:无限宽度后视提供什么优势?
    • 无限宽度的lookbehind允许使用*+量化子模式。您可能会失败或需要子模式出现在您需要的模式之前而不是紧接在它之前。
    最近更新 更多