我的英语能力很差,因为我不是英语母语人士。希望您能理解。
我已经在.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);
}
}
我的结果显示如下。
RegExpMatches
方法返回一个包含匹配项的MatchCollection
对象。但是,此对象默认情况下以lazy模式运行,这意味着它不会遍历整个字符串并立即查找所有匹配项,但始终仅在查找下一个匹配项时才查找。
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);