c# - Различия в методах сравнения строк в C #


Сравнение строки в C # довольно просто. На самом деле есть несколько способов сделать это. Я перечислил некоторые в блоке ниже. Что мне интересно узнать о различиях между ними и о том, когда нужно использовать других? Следует ли избегать любой ценой? Больше ли я не перечислял?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(Примечание: я ищу равенство в этом примере, не меньше или больше, но не стесняйтесь прокомментировать это)




Answers


Вот правила работы этих функций:

stringValue.CompareTo (otherStringValue):

  1. null перед строкой
  2. он использует CultureInfo.CurrentCulture.CompareInfo.Compare, что означает, что он будет использовать сравнение, зависящее от культуры. Это может означать, что ß будет сравниваться с SS в Германии или аналогичным

stringValue.Equals (otherStringValue):

  1. null не считается равным чему-либо
  2. если вы не укажете опцию StringComparison, она будет использовать то, что выглядит как прямая ординальная проверка равенства, т.е. ß не совпадает с SS, на любом языке или в культуре

stringValue == otherStringValue:

  1. Это не то же самое, что stringValue.Equals ().
  2. Оператор == вызывает статический метод Equals (string a, string b) (который, в свою очередь, переходит к внутреннему EqualsHelper для сравнения.
  3. Вызов .Equals () в нулевой строке получает исключение для ссылочной ссылки, а on == - нет.

Object.ReferenceEquals (stringValue, otherStringValue):

Просто проверяет, что ссылки одинаковы, т.е. это не только две строки с одним и тем же содержимым, вы сравниваете строковый объект с самим собой.

Обратите внимание, что с вышеперечисленными опциями, использующими вызовы методов, существуют перегрузки с большим количеством опций, чтобы указать, как сравнивать.

Мой совет, если вы просто хотите проверить равенство, - это решить, что вы хотите использовать сравнение, зависящее от культуры, или нет, а затем использовать .CompareTo или .Equals, в зависимости от выбора.




Из MSDN:

«Метод CompareTo был разработан в первую очередь для использования в сортировке или в алфавитном порядке. Он не должен использоваться, если основной целью вызова метода является определение того, эквивалентны две строки. Чтобы определить, эквивалентны две строки, вызовите метод Equals. "

Они предлагают использовать .Equals вместо .CompareTo если смотреть только на равенство. Я не уверен, есть ли разница между .Equals и == для класса string . Иногда я буду использовать .Equals или Object.ReferenceEquals вместо == для своих собственных классов, если кто-то появится позже и переопределит оператор == этого класса.




Если вам когда-либо нравятся различия в методах BCL, Reflector - ваш друг :-)

Я следую этим рекомендациям:

Точное совпадение: EDIT: Я ранее всегда использовал == оператор по принципу, что внутри Equals (string, string) оператор object == используется для сравнения ссылок на объекты, но кажется, что strA.Equals (strB) все еще 1-11% быстрее, чем string.Equals (strA, strB), strA == strB и string.CompareOrdinal (strA, strB). Я тестировал цикл с помощью StopWatch как с внутренними, так и с неинтерминированными строковыми значениями с одинаковой / различной длиной строк и различными размерами (от 1 до 5 МБ).

strA.Equals(strB)

Человеко-читаемый матч (западные культуры, без учета регистра):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

Человеко-читаемый матч (все другие культуры, нечувствительный случай / акцент / кана / и т. Д., Определенные CultureInfo):

string.Compare(strA, strB, myCultureInfo) == 0

Человеко-читаемое совпадение с пользовательскими правилами (Все остальные культуры):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0



Как сказал Эд , CompareTo используется для сортировки.

Однако есть разница между .Equals и ==.

== разрешает по существу следующий код:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

Простая причина заключается в следующем:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

И следующее не будет:

string a = null;
string b = "foo";

bool equal = a == b;



Хорошее объяснение и рекомендации по проблемам сравнения строк можно найти в статье « Новые рекомендации по использованию строк в Microsoft .NET 2.0», а также « Рекомендации по использованию строк в .NET Framework» .

Каждый из упомянутых методов (и других) имеет особую цель. Ключевое различие между ними заключается в том, какой тип перечисления StringComparison они используют по умолчанию. Существует несколько вариантов:

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • InvariantCulture
  • InvariantCultureIgnoreCase
  • порядковый
  • OrdinalIgnoreCase

Каждый из вышеуказанных типов сравнения задает различный прецедент:

  • порядковый
    • Внутренние идентификаторы с учетом регистра
    • Идентификаторы с учетом регистра в стандартах, таких как XML и HTTP
    • Учетные параметры, зависящие от типа
  • OrdinalIgnoreCase
    • Внутренние идентификаторы, нечувствительные к регистру
    • Идентификаторы, нечувствительные к регистру, в стандартах, таких как XML и HTTP
    • Пути файлов (в Microsoft Windows)
    • Ключи / значения реестра
    • Переменные среды
    • Идентификаторы ресурсов (например, имена дескрипторов)
    • Нечувствительные к безопасности параметры безопасности
  • InvariantCulture или InvariantCultureIgnoreCase
    • Некоторые сохраняли лингвистически-релевантные данные
    • Отображение лингвистических данных, требующих фиксированного порядка сортировки
  • CurrentCulture или CurrentCultureIgnoreCase
    • Данные, отображаемые пользователю
    • Большинство входных данных пользователя

Обратите внимание, что StringComparison Enumeration, а также перегрузки для методов сравнения строк существуют с .NET 2.0.

Метод String.CompareTo (String)

На самом деле это безопасная реализация метода IComparable.CompareTo . Учет по умолчанию: CurrentCulture.

Применение:

Метод CompareTo был разработан в основном для использования в сортировке или в алфавитном порядке

таким образом

Внедрение интерфейса IComparable обязательно будет использовать этот метод

Метод String.Compare

Статический член класса String, который имеет много перегрузок. Учет по умолчанию: CurrentCulture.

Когда это возможно, вы должны вызвать перегрузку метода Compare, который включает параметр StringComparison.

Метод String.Equals

Override из класса Object и перегружен для безопасности типов. Учет по умолчанию: ординал. Заметить, что:

Методы равенства класса String включают статические Equals , статический оператор == и метод экземпляра Equals .

Класс StringComparer

Существует также другой способ справиться со строковыми сравнениями, особенно для сортировки:

Вы можете использовать класс StringComparer для создания сопоставления типа для сортировки элементов в общей коллекции. Классы, такие как Hashtable, Dictionary, SortedList и SortedList, используют класс StringComparer для сортировки.




Не то, что производительность обычно имеет значение в 99% случаев, когда вам нужно это делать, но если вам нужно было сделать это в цикле несколько миллионов раз, я бы настоятельно предложил использовать .Equals или ==, потому что, как только он найдет символ который не соответствует ему, выдает все это как ложное, но если вы используете CompareTo, ему придется выяснить, какой символ меньше, чем другой, что приводит к немного худшему времени исполнения.

Если ваше приложение будет работать в разных странах, я бы рекомендовал вам взглянуть на последствия CultureInfo и, возможно, использовать .Equals. Поскольку я действительно пишу приложения для США (и не волнует, если кто-то не работает должным образом), я всегда просто использую ==.




В тех формах, которые вы указали здесь, между ними нет большой разницы. CompareTo заканчивает вызов метода CompareInfo который выполняет сравнение с использованием текущей культуры; Equals вызывается оператором == .

Если вы рассматриваете перегрузки, тогда все становится по-другому. Compare и == могут использовать текущую культуру для сравнения строки. Equals и String.Compare могут принимать аргумент перечисления StringComparison который позволяет вам определять нечувствительные к культуре или без учета регистра. Только String.Compare позволяет указать CultureInfo и выполнять сравнения с использованием культуры, отличной от культуры по умолчанию.

Из-за своей универсальности я считаю, что я использую String.Compare больше, чем любой другой метод сравнения; он позволяет мне точно указать, что я хочу.




Одна большая разница в примечании: .Equals () генерирует исключение, если первая строка имеет значение null, а == === =============

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");



Использование .Equals также намного легче читать .




CompareTo сравнивает строку со строковым объектом и возвращает значение int. Если значение равно 0, значит, строки равны.

string country = "southindia";
object ob1 = country.Clone();
Console.WriteLine( country.CompareTo(ob1));

string country = "southindia";
string cou = "insia";
int n = country.CompareTo(cou);
Console.WriteLine( n );



с .Equals, вы также получаете опции StringComparison. очень удобно для игнорирования случая и других вещей.

btw, это будет оцениваться как false

string a = "myString";
string b = "myString";

return a==b

Поскольку == сравнивает значения a и b (которые являются указателями), это будет оценивать только true, если указатели указывают на один и тот же объект в памяти. .Equals разыгрывает указатели и сравнивает значения, хранящиеся в указателях. a.Equals (b) будет здесь.

и если вы измените b на:

b = "MYSTRING";

то a.Equals (b) является ложным, но

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

было бы правдой

a.CompareTo (b) вызывает функцию CompareTo в строке, которая сравнивает значения в указателях и возвращает <0, если значение, хранящееся в a, меньше значения, сохраненного в b, возвращает 0, если a.Equals (b) истинно, и > 0 в противном случае. Тем не менее, это чувствительно к регистру, я думаю, что есть возможности для CompareTo игнорировать случай и т. Д., Но у меня нет времени смотреть сейчас. Как уже указывали другие, это будет сделано для сортировки. Сопоставление для равенства таким образом приведет к ненужным накладным расходам.

Я уверен, что я оставляю вещи, но я думаю, что для этого достаточно информации, чтобы начать экспериментировать, если вам нужно больше деталей.