使用忽略大小写的正则表达式比使用字符串的ToLower方法更快吗?

4

鉴于像这样的字符串:

string s1 = "Abc";
string s2 = "ABC";

哪个更快:

Regex.Match(s1, s2, RegexOptions.IgnoreCase)

或者

s1.ToLower() == s2.ToLower()

如果它们相同或其中一个更快,那么什么时候使用哪个更好?

通常情况下,普通字符串操作比正则表达式更快。 - fardjad
1
Regex.Match非常不准确。无论如何,它都不是一个可行的解决方案。正则表达式不是字符串 - 它是一个正则表达式模式。 - usr
@fardjad,为什么正则表达式通常较慢? - theateist
7个回答

8

也许第二种方法更快,但我会避免使用这两种方法。

更好的方法是使用适当的StringComparison参数和方法string.Equals

s1.Equals(s2, StringComparison.CurrentCultureIgnoreCase)

在线查看运行结果:ideone


请考虑s2为无效正则表达式的情况,然后返回+1。 - user7116

4
理论上来说,比较 2 个字符串应该更快,正则表达式被认为是相当慢的。
然而,如果您想将一个字符串 s1 与一个正则表达式 s2 进行匹配并忽略大小写(这不同于比较两个字符串),那么第一种解决方案更好,因为它应该避免创建另一个字符串。
像这样的问题,我通常会运行基准测试并比较性能 :)

1
我会点赞指出基准测试是回答这些问题的最佳方式,但今天我的投票已经用完了! - Andrew Barber

4

@Mark Byers已经发布了正确的答案。

我想强调你不应该使用ToLower进行字符串比较。这是不正确的。

s1.Equals(s2, StringComparison.CurrentCultureIgnoreCase) //#1
s1.ToLower() == s2.ToLower() //#2
s1.ToLowerInvariant() == s2.ToLowerInvariant() //#3

涉及到异国语言和奇特字符时,(2) 和 (3) 都是不正确的。土耳其语的"I" 是经典例子。

始终使用 #1,即使在哈希表中也是如此。

(除非有非常特殊的情况)


3

需要注意的是,Regex.Match(s1, s2, RegexOptions.IgnoreCase)在一般情况下不是检查不区分大小写的相等性的安全方法。考虑当s2".*"的情况。无论s1是什么,Regex.Match都将返回true!


3
这可能是我见过的 过早优化 最极端的例子。相信我,你永远不会遇到这种情况。不要听那些告诉你要避免使用正则表达式因为“它们很慢”的人。糟糕编写的正则表达式确实会消耗大量资源,但这是编写正则表达式的人的问题。合理精心制作的正则表达式对于人们应用它们的绝大多数任务来说足够快了。

0

比较会更快,但是不要将字符串转换为小写或大写然后再进行比较,最好使用可以忽略大小写的相等比较。例如:

        s1.Equals(s2, StringComparison.OrdinalIgnoreCase)

0

这里是三种方法的小比较:

正则表达式:282毫秒 ToLower:67毫秒 Equals:34毫秒

public static void RunSnippet()
{
    string s1 = "Abc";
    string s2 = "ABC";

    // Preload
    compareUsingRegex(s1, s2);
    compareUsingToLower(s1, s2);
    compareUsingEquals(s1, s2);

    // Regex
    Stopwatch swRegex = Stopwatch.StartNew();
    for (int i = 0; i < 300000; i++) 
        compareUsingRegex(s1, s2);
    Console.WriteLine(string.Format("Regex: {0} ms", swRegex.ElapsedMilliseconds));

    // ToLower
    Stopwatch swToLower = Stopwatch.StartNew();
    for (int i = 0; i < 300000; i++) 
        compareUsingToLower(s1, s2);
    Console.WriteLine(string.Format("ToLower: {0} ms", swToLower.ElapsedMilliseconds));

    // ToLower
    Stopwatch swEquals = Stopwatch.StartNew();
    for (int i = 0; i < 300000; i++) 
        compareUsingEquals(s1, s2);
    Console.WriteLine(string.Format("Equals: {0} ms", swEquals.ElapsedMilliseconds));
}

private static bool compareUsingRegex(string s1, string s2) 
{
    return Regex.IsMatch(s1, s2, RegexOptions.IgnoreCase);
}

private static bool compareUsingToLower(string s1, string s2) 
{
    return s1.ToLower() == s2.ToLower();
}

private static bool compareUsingEquals(string s1, string s2) 
{
    return s1.Equals(s2, StringComparison.CurrentCultureIgnoreCase);
}

这不是一个公平的比较。我尝试提前创建Regex对象并将其存储在静态变量中,然后调用IsMatch()方法,结果如下:Regex: 71msToLower: 51 msEquals: 23 ms - Alan Moore
这也不是一个有用的比较,因为s2包含实际正则表达式的情况。 - user7116
要求是进行字符串比较并忽略大小写。当然,如果您说s1永远不会改变,那么您可以进行多个优化(在这种情况下,您可以编译/保留正则表达式对象)。 - Fabske

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接