Является ли String.Contains() быстрее, чем String.IndexOf()?

У меня есть строковый буфер длиной около 2000 символов и нужно проверить буфер, если он содержит определенную строку.
Будет выполнять проверку в ASP.NET 2.0 webapp для каждого веб-запроса.

Кто-нибудь знает, работает ли метод String.Contains, String.IndexOf метод?

    // 2000 characters in s1, search token in s2
    string s1 = "Many characters. The quick brown fox jumps over the lazy dog"; 
    string s2 = "fox";
    bool b;
    b = s1.Contains(s2);
    int i;
    i = s1.IndexOf(s2);

Забавный факт

Ответ 1

Contains вызывает IndexOf:

public bool Contains(string value)
{
    return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Что вызывает CompareInfo.IndexOf, который в конечном итоге использует реализацию CLR.

Если вы хотите посмотреть, как строки сравниваются в CLR это покажет вам (ищите CaseInsensitiveCompHelper).

IndexOf(string) не имеет параметров, а Contains() использует сравнительное сравнение (побайтовое сравнение вместо попыток выполнить интеллектуальное сравнение, например e с помощью é).

Итак, IndexOf будет немного быстрее (теоретически), поскольку IndexOf переходит прямо в строковый поиск, используя FindNLSString из kernel32.dll(мощность рефлектора!).

Обновлено для .NET 4.0. IndexOf больше не использует сравнительное сравнение, поэтому Contains может быть быстрее. См. Комментарий ниже.

Ответ 3

Содержит (s2) много раз (на моем компьютере 10 раз) быстрее, чем IndexOf (s2), потому что Contains использует StringComparison.Ordinal, который быстрее, чем чувствительный к культуре поиск, который IndexOf делает по умолчанию (но это может измениться в .net 4.0 http://davesbox.com/archive/2008/11/12/breaking-changes-to-the-string-class.aspx).

Содержит в моих тестах ту же производительность, что и IndexOf (s2, StringComparison.Ordinal) >= 0, но она короче и делает ваше намерение понятным.

Ответ 4

Используя Reflector, вы можете видеть, что Contains реализуется с помощью IndexOf. Здесь реализация.

public bool Contains(string value)
{
   return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Содержит, скорее всего, немного медленнее, чем прямое обращение к IndexOf, но я сомневаюсь, что это будет иметь какое-то значение для реальной производительности.

Ответ 5

Я запускаю реальный случай (в отличие от синтетического теста)

 if("=,<=,=>,<>,<,>,!=,==,".IndexOf(tmps)>=0) {

против

 if("=,<=,=>,<>,<,>,!=,==,".Contains(tmps)) {

Это жизненно важная часть моей системы, и она выполнена 131,953 раза (спасибо DotTrace).

Однако шокирующий сюрприз, результат - это то, что ожидалось

  • IndexOf 533ms.
  • Содержит 266 мс.

: -/

net framework 4.0 (обновлено по состоянию на 13-02-2012)

Ответ 6

Если вы действительно хотите оптимизировать свой микрокомпьютер, ваш лучший подход - это всегда бенчмаркинг.

Структура .net имеет отличную реализацию секундомера - System.Diagnostics.Stopwatch

Ответ 7

Так же, как обновление к этому, я проводил некоторое тестирование и предоставляю вашу входную строку довольно большой, а затем параллельный Regex - это самый быстрый метод С#, который я нашел (при условии, что у вас есть более одного ядра, которое я себе представляю)

Получение общего количества совпадений, например -

needles.AsParallel ( ).Sum ( l => Regex.IsMatch ( haystack , Regex.Escape ( l ) ) ? 1 : 0 );

Надеюсь, это поможет!

Ответ 8

Используйте эталонную библиотеку, например этот недавний набег от Jon Skeet для ее измерения.

Caveat Emptor

Как и все (микро-) вопросы производительности, это зависит от версий используемого программного обеспечения, деталей проверенных данных и кода, связанного с вызовом.

Как и все (микро-) вопросы производительности, первым шагом должно быть получение текущей версии, которая легко поддерживается. Тогда бенчмаркинг, профилирование и настройка могут быть применены к измеренным узким местам, а не гадать.

Ответ 9

Из небольшого чтения видно, что под капотом метод String.Contains просто вызывает String.IndexOf. Разница заключается в String.Contains возвращает логическое значение, а String.IndexOf возвращает целое число с (-1), представляющее, что подстрока не была найдена.

Я бы посоветовал написать небольшой тест со 100 000 итерационными итерациями и убедиться в этом сами. Если бы я догадался, я бы сказал, что IndexOf может быть немного быстрее, но, как я сказал, это просто предположение.

У Джеффа Этвуда есть хорошая статья о струнах в его блоге. Это больше о конкатенации, но может быть полезно, тем не менее.

Ответ 10

Для тех, кто все еще читает это, indexOf(), вероятно, лучше работает на большинстве корпоративных систем, так как contains() несовместим с IE!