簡體   English   中英

查看字符串是否包含C#中的另一個字符串的最快,不區分大小寫的方法是什么?

[英]What is the fastest, case insensitive, way to see if a string contains another string in C#?

編輯2:

確認我的性能問題是由於對StringExtensions類的靜態函數調用造成的。 一旦刪除,IndexOf方法確實是實現此目的的最快方法。

查看字符串是否包含C#中的另一個字符串的最快,不區分大小寫的方法是什么? 我在這里看到了Case不敏感的'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;
} 

ToUpper的:

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

正則表達式:

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

所以我的問題是,這實際上是平均最快的方式,為什么呢?

編輯:

這是我用來突出性能差異的簡單測試應用程序。 使用它,我看到ToLower()為16 ms,ToUpper為18 ms,StringExtensions.Contains()為140 ms:

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

我發現編譯后的RegEx是目前最快的解決方案,顯然更加通用。 編譯它有助於使其與較小的字符串比較相提並論,如您所述,沒有與較大的字符串進行比較。

http://www.dijksterhuis.org/regular-expressions-advanced/包含一些提示,以便從RegEx比較中獲得最大速度; 你會發現它很有幫助。

這對我來說很有趣,所以我用不同的方法創建了一個小測試

string content = "";
            for (var i = 0; i < 10000; i++)
                content = String.Format("{0} asldkfjalskdfjlaskdfjalskdfj laksdf lkwiuirh 9238 r9849r8 49834", content);

            string test = String.Format("{0} find_me {0}", content);

            string search = test;

            var tickStart = DateTime.Now.Ticks;
            //6ms
            //var b = search.ToUpper().Contains("find_me".ToUpper());

            //2ms
            //Match m = Regex.Match(search, "find_me", RegexOptions.IgnoreCase);


            //a little bit over 1ms
            var c = false;
            if (search.Length == search.ToUpper().Replace("find_me".ToUpper(), "x").Length)
                c = true;
            var tickEnd = DateTime.Now.Ticks;
            Debug.Write(String.Format("{0} {1}", tickStart, tickEnd));

所以我所做的就是創建一個字符串並在其中搜索

第一種方法search.ToUpper().Contains("find_me".ToUpper()) 5ms

第二種方法Match m = Regex.Match(search, "find_me", RegexOptions.IgnoreCase) 2ms

第三種方法

if (search.Length == search.ToUpper().Replace("find_me".ToUpper(), "x").Length)
                c = true;

花了不到1毫秒

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM