c# - 在 C# 中查看一个字符串是否包含另一个字符串的最快、不区分大小写的方法是什么?

标签 c# .net string

编辑 2:

确认我的性能问题是由于对 StringExtensions 类的静态函数调用造成的。删除后,IndexOf 方法确实是完成此操作的最快方法。

在 C# 中查看一个字符串是否包含另一个字符串的最快、不区分大小写的方法是什么?我在 Case insensitive 'Contains(string)' 看到该帖子的公认解决方案但我已经做了一些初步的基准测试,似乎使用该方法会导致在找不到测试字符串时对较大字符串(> 100 个字符)的调用速度降低几个数量级。

以下是我知道的方法:

索引:

public static bool Contains(this string source, string toCheck, StringComparison comp)
{
    if (string.IsNullOrEmpty(toCheck) || string.IsNullOrEmpty(source))
        return false;

    return source.IndexOf(toCheck, comp) >= 0;
} 

到上层:

source.ToUpper().Contains(toCheck.ToUpper());

正则表达式:

bool contains = Regex.Match("StRiNG to search", "string", RegexOptions.IgnoreCase).Success;

所以我的问题是,平均而言哪种方式确实最快,为什么会这样?

编辑:

这是我用来强调性能差异的简单测试应用程序。使用它,我看到 ToLower() 为 16 毫秒,ToUpper 为 18 毫秒,StringExtensions.Contains() 为 140 毫秒:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace ScratchConsole
{
    class Program
    {
    static void Main(string[] args)
    {
        string input = "";
        while (input != "exit")
        {
            RunTest();
            input = Console.ReadLine();
        }
    }

    static void RunTest()
    {
        List<string> s = new List<string>();
        string containsString = "1";
        bool found;
        DateTime now;
        for (int i = 0; i < 50000; i++)
        {
            s.Add("AAAAAAAAAAAAAAAA AAAAAAAAAAAA");
        }

        now = DateTime.Now;
        foreach (string st in s)
        {
            found = st.ToLower().Contains(containsString);
        }
        Console.WriteLine("ToLower(): " + (DateTime.Now - now).TotalMilliseconds);

        now = DateTime.Now;
        foreach (string st in s)
        {
            found = st.ToUpper().Contains(containsString);
        }
        Console.WriteLine("ToUpper(): " + (DateTime.Now - now).TotalMilliseconds);


        now = DateTime.Now;
        foreach (string st in s)
        {
            found = StringExtensions.Contains(st, containsString, StringComparison.OrdinalIgnoreCase);
        }
        Console.WriteLine("StringExtensions.Contains(): " + (DateTime.Now - now).TotalMilliseconds);

    }
}

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source.IndexOf(toCheck, comp) >= 0;
    }
}

最佳答案

由于 ToUpper 实际上会导致创建一个新字符串,因此 StringComparison.OrdinalIgnoreCase 会更快,而且,正则表达式对于像这样的简单比较有很多开销。也就是说, String.IndexOf(String, StringComparison.OrdinalIgnoreCase) 应该是最快的,因为它不涉及创建新字符串。

我猜(我又来了)RegEx 有更好的最坏情况,因为它如何评估字符串,IndexOf 将始终进行线性搜索,我猜(再一次)RegEx 使用了一些东西更好的。 RegEx 也应该有一个最好的情况,它可能接近,但不如 IndexOf 好(由于它的语言更复杂)。

15,000 length string, 10,000 loop

00:00:00.0156251 IndexOf-OrdinalIgnoreCase
00:00:00.1093757 RegEx-IgnoreCase 
00:00:00.9531311 IndexOf-ToUpper 
00:00:00.9531311 IndexOf-ToLower

Placement in the string also makes a huge difference:

At start:
00:00:00.6250040 Match
00:00:00.0156251 IndexOf
00:00:00.9687562 ToUpper
00:00:01.0000064 ToLower

At End:
00:00:00.5781287 Match
00:00:01.0468817 IndexOf
00:00:01.4062590 ToUpper
00:00:01.4218841 ToLower

Not Found:
00:00:00.5625036 Match
00:00:01.0000064 IndexOf
00:00:01.3750088 ToUpper
00:00:01.3906339 ToLower

关于c# - 在 C# 中查看一个字符串是否包含另一个字符串的最快、不区分大小写的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7759902/

相关文章:

c# - 任务重复?

c# - 耦合到依赖注入(inject)框架

c# - 在解决方案中使用另一个项目的功能

c - 字符串使用的字符单元格数

c# - ObservableCollection 方法 add() 阻塞

c# - 在注册表中创建子上下文菜单项

c# - 根据用户角色呈现 HTML 内容?

c# - .NET Framework 版本冲突问题

string - 如何在 Go 中将整个字符串保存为 txt 文件?

objective-c - 有没有办法通过名称获取类(class)?