为什么Regex的Matches功能这么快?

问题描述 投票:0回答:1

我的英语能力很差,因为我不是英语母语人士。希望您能理解。

我已经在.Net中使用了Regex函数。有一天,我尝试了使用117000字符串和46种模式调用Regex的Matches函数的测试。结果,比2ms更快地生成了51870个令牌。

这里很棒的事情是只花了2毫秒。将生成的集合转换为List需要250毫秒。 (代码如下)。

var list = collection.Cast<Match>().Select(match => match.Value).ToList();

我简直不敢相信,所以我尝试了几次,结果也一样。

我很好奇为什么匹配Regex功能这么快。是否在内部使用异步或并行机制?

在测试中,我像下面这样调用该函数。

var collection = Regex.Matches(targetString(117000), this.rule(46), RegexOptions.Multiline | RegexOptions.ExplicitCapture);

感谢您阅读。


完整的源代码如下。请在test.txt中输入许多字符串。为了简单起见,我删除了“ \ r”,“ \ n”,“ \ t”模式。结果,生成的令牌的数量为45450。谢谢您的关注。

class Program
{
    static void Main(string[] args)
    {
        string targetString = File.ReadAllText("test.txt");

        string pattern = "(\\breturn\\b)|(\\bwhile\\b)|(\\bconst\\b)|(\\belse\\b)|(\\bvoid\\b)|(\\bint\\b)|(\\bif\\b)|" +
    "([_a-zA-Z][_a-zA-Z0-9]*)|([0-9]+)|" +
    "(//.*$)|(\\!\\=)|(\\%\\=)|(\\>\\=)|(\\/\\=)|(\\+\\=)|(\\|\\|)|(\\-\\-)|(\\+\\+)|(\\*\\=)|(\\-\\=)|(\\<\\=)|(\\=\\=)|(\\&\\&)|(\\*\\/)|(\\/\\*)|(\\*)|(\\!)|(\\+)|(\\%)|(\\))|(\\;)|(\\()|(\\/)|" +
    "(\\{)| (\\})| (\\-)| (\\])| (\\[)|(\\,)|(\\>)|(\\ )|(\\=)|(\\<)";


        Stopwatch sw = new Stopwatch();
        sw.Start();

        var collection = Regex.Matches(targetString, pattern, RegexOptions.Multiline | RegexOptions.ExplicitCapture);

        sw.Stop();
        Console.WriteLine("Elapsed={0}", sw.Elapsed);

        sw = new Stopwatch();
        sw.Start();

        var list = collection.Cast<Match>().Select(match => match.Value).ToList();

        sw.Stop();
        Console.WriteLine("Elapsed={0}", sw.Elapsed);
    }
}

我的结果显示如下。

enter image description here

enter image description here

enter image description here

c# regex
1个回答
3
投票

RegExpMatches方法返回一个包含匹配项的MatchCollection对象。但是,此对象默认情况下以lazy模式运行,这意味着它不会遍历整个字符串并立即查找所有匹配项,但始终仅在查找下一个匹配项时才查找。

Documentation

MatchCollection对象根据需要在逐个匹配项中填充基础。它等效于正则表达式引擎调用Regex.Match方法重复并将每个匹配项添加到集合中。通过集合的集合访问集合时使用此技术GetEnumerator方法,或使用foreach访问该方法语句(在C#中)或For Each ... Next语句(在Visual Basic中)。

因此,在您的代码中,仅当您尝试将Matches()转换为MatchCollection时,才在调用List时不进行实际搜索。


为了测量模式搜索的全部时间,您可以通过从代码访问Count属性来强制进行直接评估。

Stopwatch sw = new Stopwatch();
sw.Start();

var collection = Regex.Matches(targetString, pattern, RegexOptions.Multiline | RegexOptions.ExplicitCapture);

int count = collection.Count; // Force immediate full evaluation

sw.Stop();
Console.WriteLine("Found {0}, Elapsed={1}", count, sw.Elapsed);
© www.soinside.com 2019 - 2024. All rights reserved.