You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中匹配句号前平衡括号内字符串的正则匹配问题

搞定C#中平衡括号+句号前的正则匹配问题

嘿,我明白你现在的困扰——想用带平衡组的正则匹配句号前、完全闭合的括号内的字符串,但遇到多余左括号时就失效了。咱们来一步步捋清楚问题,然后给出靠谱的解决方案。

先说说你现有正则的问题

你原来的正则@"(?<Par>[(]).+(?<-Par>[)])(?(Par)(?!))\."和修改后的版本,主要有两个坑:

  • .+太贪婪:它会直接匹配到最后一个右括号,完全不管中间的嵌套括号,导致平衡组的计数完全乱掉,根本没法正确统计括号的开闭情况。
  • 条件断言的位置不对:就算加了(?(Par)(?!)),但因为前面的贪婪匹配已经走了错误的路径,这个断言没法提前阻止错误的匹配尝试。

修正后的正则方案

我给你调整了正则的结构,改用原子组配合平衡组,同时严格确保括号完全平衡,而且只匹配句号前的有效内容:

@"\((?>[^()]+|(?<Par>\()|(?<-Par>\)))+(?(Par)(?!))\."

给你拆解开解释下:

  • \(:先锁定开头的左括号,确保我们从合法的括号起始处开始匹配
  • (?>[^()]+|(?<Par>\()|(?<-Par>\)))+:这个原子组是核心,避免回溯干扰平衡计数:
    • [^()]+:匹配任何非括号的普通字符
    • (?<Par>\():碰到左括号,就往Par栈里加一个标记
    • (?<-Par>\)):碰到右括号,就从Par栈里删掉一个标记
    • +:重复这个逻辑,直到没法匹配为止
  • (?(Par)(?!)):关键的条件断言——如果Par栈里还有剩余标记(也就是还有未闭合的左括号),直接让匹配失败
  • \.:最后匹配结尾的句号

测试验证一下

把这个正则替换到你的测试代码里,之前失败的用例就能正常工作了:

string[] tests = { 
    "a.c", "", 
    "a).c", "", 
    "(a.c", "", 
    "a(a).c", "(a).", 
    "a(a b).c", "(a b).", 
    "a((a b)).c", "((a b)).", 
    "a(((a b))).c", "(((a b))).", 
    "a((a) (b)).c", "((a) (b)).", 
    "a((a)(b)).c", "((a)(b)).", 
    "a((ab)).c", "((ab)).", 
    "a)((ab)).(c", "((ab)).", 
    "a(((a b)).c", "", 
    "a(((a b))).)c", "(((a b)))." 
}; 
Regex re = new Regex(@"\((?>[^()]+|(?<Par>\()|(?<-Par>\)))+(?(Par)(?!))\."); 
for (int i = 0; i < tests.Length; i += 2) { 
    var result = re.Match(tests[i]).Groups[0].Value; 
    if (result != tests[i + 1]) 
        throw new Exception ("Expecting: " + tests[i + 1] + ", got " + result); 
}

比如之前失败的"a(((a b)).c",因为里面的左括号没完全闭合,条件断言会直接让匹配失败,返回空字符串,完全符合你的预期。

额外提个小细节

用原子组(?>...)是为了避免不必要的回溯,既能提升正则的运行效率,还能保证平衡组的计数不会因为回溯被打乱,特别适合处理嵌套结构的匹配。

内容的提问来源于stack exchange,提问作者rednoyz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:18:05