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

时间:2019-11-30 20:31:54

标签: c# regex

我的英语能力很差,因为我不会说英语。 希望您能理解。

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

这里令人惊讶的事情是只花了2ms。 将生成的集合转换为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

1 个答案:

答案 0 :(得分:3)

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

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);