进行单个字符通配符搜索时,Regex IsMatch 真的很慢

Regex IsMatch really slow when doing a single character wildcard search

我们遇到这样一种情况,即在开始时使用单个字符进行通配符搜索,然后在通配符之后使用其他字符进行通配符搜索,并且 运行 速度非常慢(至少在 c# 中是这样)。 这有什么原因和改善方法吗?它在几乎所有其他情况下都更快。

20k 长随机字符串的示例 运行 1000 次:

绝对不是随机字符串,因为已经尝试过不同的。

模式肯定是,如果第一部分是单个字符,然后是通配符后的任何字符,它总是慢得多。

--更新--

我想知道 Regex 的工作方式是否是循环查找单个字符,当它找到它时,它会一直搜索直到结束寻找下一个模式。当它找不到它时,它会返回到第一个字符并开始寻找下一个第一个字符,直到它再次找到第一个匹配项并执行一些完整的逻辑,即使它可以跳过它在第一个 运行.

我想我已经通过生成一个没有字符“a”的随机字符串来证实这一点——如果我随后使用这个字符作为第一个字符,它真的很快,但是如果我使用“c”它很慢。即 a.*b.*r1f 在这种情况下是即时的,但 c.*b.*r1f 需要很长时间。

如果是这样,想知道您是否可以通过某种方式在正则表达式中对其进行优化?

这种性能差异的原因在于优化搜索的方式。

当模式以文字字符开头时,在正则表达式引擎的“正常遍历”之前使用快速算法来查找字符串中模式可能成功的可能位置(文字子字符串所在的位置)。然后正则表达式引擎仅在这些位置测试模式。

这就是为什么以字母 a 开头的模式,对于不包含字母 'a' 的字符串(无论大小)很快解决的原因(不匹配,整个模式从未经过测试。

现在为什么对于同一种模式,以字母 a 开头的模式(只有一个文字字符)和以 abcd 开头的模式在大多数情况下会给出不同的表现随机字符串。答案很简单,四个字符 abcd 的位置比只有 a 的位置出现的频率低。更少的尝试位置 => 更快的结果。


另请注意,像 a.*b.*c 这样的模式称为病态模式,因为它可能导致回溯步骤数量的潜在爆炸。如果使用非贪婪量词有时可以减少问题,则不能保证它总是会提高性能(这不是魔杖)。最好的方法始终是使用适当的字符 类、适当的量词和最准确的字符串描述来做到最精确,尽可能避免使用 .*.*?a[^b]*b[^c]*c 例如。