c#正则表达式速度问题
c# Regular Expression speed issue
我在 C# 中有一个正则表达式,其中的模式是 8000 多个单词(或单词组),每个单词由单词边界分隔,即:
"\bword1\b|\bword2 word3 word4\b|.......etc"
我正在尝试将字符串中的一个词(或一组词)与该表达式中的任何一个词(或一组词)相匹配。一切正常,除了我发现平均需要 37 毫秒才能完成操作。
有趣的是,如果我做同样的事情但使用 String.IndexOf
和一些复杂的方法,它确实运行得更快(但仍然太慢),我觉得这很奇怪。
我特别了解其他正则表达式引擎 re2/google,但我真的很想尽可能使用 C# 内置功能。
如果有人有建议,我们将不胜感激。
要了解正则表达式运行缓慢的原因,您必须简单地想象一下正则表达式的工作原理。
你的情况(8000 个备选方案)
- 第 1 步。从输入字符 0 开始。
- 第 2 步。尝试匹配备选方案 0。糟糕,没有匹配。
- 第 3 步。尝试匹配备选方案 1。糟糕,没有匹配。
- ...
- 第 4000 步。尝试匹配备选 4001。耶!第一个字符匹配!
- 第 4001 步。尝试匹配备选 4001。耶!第二个字符匹配!
- 步骤 4002。尝试匹配备选 4001。糟糕,没有匹配。
- 步骤 4003。尝试匹配备选 4002。糟糕,没有匹配。
- ...
- 第 8963 步。尝试匹配备选 7999。糟糕,没有匹配。
- 步骤 8964。输入字符 0 处的所有备选方案均失败。
- 第8965步。移动到输入字符1。
- 第 8966 步。尝试匹配替代项 0。糟糕,没有匹配。
- ...
输入字符串越长,正则表达式的替代项越多,输入字符串中出现的 "almost, but not quite" 匹配项越多,速度就越慢。
如果 String.IndexOf()
可以让它更快,那就去做吧。你永远不会用正则表达式让它变得更快。
探索在字符串中搜索单词的其他方法。哪一个适合您在很大程度上取决于您输入的内容。
我建议切换到 HashSet
,因为它似乎更适合您的任务。
这是您可以执行的操作的草稿:
// produce string[] containing your words
var words = myRegexp.split("\b|\");
var mySet = new HashSet<string>(words);
// usage
mySet.Contains("find this");
我在 C# 中有一个正则表达式,其中的模式是 8000 多个单词(或单词组),每个单词由单词边界分隔,即:
"\bword1\b|\bword2 word3 word4\b|.......etc"
我正在尝试将字符串中的一个词(或一组词)与该表达式中的任何一个词(或一组词)相匹配。一切正常,除了我发现平均需要 37 毫秒才能完成操作。
有趣的是,如果我做同样的事情但使用 String.IndexOf
和一些复杂的方法,它确实运行得更快(但仍然太慢),我觉得这很奇怪。
我特别了解其他正则表达式引擎 re2/google,但我真的很想尽可能使用 C# 内置功能。
如果有人有建议,我们将不胜感激。
要了解正则表达式运行缓慢的原因,您必须简单地想象一下正则表达式的工作原理。
你的情况(8000 个备选方案)
- 第 1 步。从输入字符 0 开始。
- 第 2 步。尝试匹配备选方案 0。糟糕,没有匹配。
- 第 3 步。尝试匹配备选方案 1。糟糕,没有匹配。
- ...
- 第 4000 步。尝试匹配备选 4001。耶!第一个字符匹配!
- 第 4001 步。尝试匹配备选 4001。耶!第二个字符匹配!
- 步骤 4002。尝试匹配备选 4001。糟糕,没有匹配。
- 步骤 4003。尝试匹配备选 4002。糟糕,没有匹配。
- ...
- 第 8963 步。尝试匹配备选 7999。糟糕,没有匹配。
- 步骤 8964。输入字符 0 处的所有备选方案均失败。
- 第8965步。移动到输入字符1。
- 第 8966 步。尝试匹配替代项 0。糟糕,没有匹配。
- ...
输入字符串越长,正则表达式的替代项越多,输入字符串中出现的 "almost, but not quite" 匹配项越多,速度就越慢。
如果 String.IndexOf()
可以让它更快,那就去做吧。你永远不会用正则表达式让它变得更快。
探索在字符串中搜索单词的其他方法。哪一个适合您在很大程度上取决于您输入的内容。
我建议切换到 HashSet
,因为它似乎更适合您的任务。
这是您可以执行的操作的草稿:
// produce string[] containing your words
var words = myRegexp.split("\b|\");
var mySet = new HashSet<string>(words);
// usage
mySet.Contains("find this");