C#中正则表达式模式\K的替代方法

9
我有一个正则表达式,我在 http://gskinner.com/RegExr/ 上进行了测试,它有效,但当我在我的C#应用程序中使用它时失败了。

我的正则表达式:(?<!\d)\d{6}\K\d+(?=\d{4}(?!\d)) 文本:4000751111115425 结果:111111

我的正则表达式哪里出了问题?


3
.NET的正则表达式引擎不支持\K。我认为最接近的替代方法是使用(?<!\d)\d{6}(\d+)(?=\d{4}(?!\d)),然后查看match.Groups[1].Value而不是match.Value。(注:如果没有♦一次性关闭此问题,这将是一个答案。) - Rawling
3
我认为你过于复杂化了。 (?<=\d{6})\d+(?=\d{4}) 同样可以工作,因为 + 是贪婪的。 - Rawling
.NET正则表达式实现不支持\K:https://dev59.com/questions/dmYr5IYBdhLWcg3wmLVk,这可以通过使用后向引用或捕获组来解决。 - jessehouwing
1
@Rawling,现在你好像可以把你的答案发布为一个答案了。 - mickmackusa
2个回答

8

您遇到的问题是,.NET正则表达式不支持\K,即“放弃已匹配的内容”。

我认为您的正则表达式的含义是“匹配超过十个\d数字的任何字符串,并尽可能多地匹配数字,然后丢弃前6个数字和最后4个数字”。

我认为符合.NET标准的正则表达式是:

(?<=\d{6})\d+(?=\d{4})

实现相同的效果。请注意,对于没有更多\d的负向先行/后行并不是必需的,因为\d+是贪婪的——引擎已经会尝试匹配尽可能多的数字。


如果我有这个正则表达式(将从标签中删除空格)\s\S*(?:<p class="text_obisnuit">|\G)(?:(?!</p>).)*?\s\K\s+|(?<=<p class="text_obisnuit">)\s+|\s+(?=</p>),那么 \K 的替代方案是什么? - Just Me
@JustMe 我觉得你可以把 \K 前面的部分放到正向先行断言里,就像第二个备选方案已经使用的那样 ((?<= ... ))。 - Rawling

0
通常情况下,\K操作符(用于从匹配内存缓冲区中丢弃到目前为止所有已匹配的文本)可以通过两种技术来模拟: 例如,
  • PCRE a+b+c+=\K\d+ (demo) = .NET (?<=a+b+c+=)\d+a+b+c+=(\d+)(并捕获第 1 组的值)
  • PCRE ^[^][]+\K.* (demo) = .NET (?<=^[^][]+)(?:\[.*)?$ (demo) 或(更好的写法)^[^][]+(.*) (demo)。
第二个示例的问题在于[^][]+可以匹配与.*相同的文本(这些模式重叠),并且由于两个模式之间没有明确的边界,仅使用回顾后查找实际上不起作用,需要额外的技巧才能使其工作。

捕获组方法是通用的,在所有情况下都应该有效。

由于\K使正则表达式引擎“忘记”到目前为止消耗的匹配部分,因此在此处最好的方法是使用捕获组来获取左侧上下文后需要获取的匹配部分:

using System;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main()
    {
        var text = "Text  4000751111115425";
        var result = Regex.Match(text, @"(?<!\d)\d{6}(\d+)(?=\d{4}(?!\d))")?.Groups[1].Value;
        Console.WriteLine($"Result: '{result}'");
    }
}

请查看在线C#演示正则表达式演示(请参见Table选项卡以查看正确的结果表格)。 详情
  • (?<!\d) - 左手数字边界
  • \d{6} - 六个数字
  • (\d+) - 捕获组1:一个或多个数字
  • (?=\d{4}(?!\d)) - 正向先行断言,匹配紧随其后的位置,紧跟着四个数字,不再紧跟着另一个数字。

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