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

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

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

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

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

Ответ 1

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

stringValue.CompareTo(otherStringValue):

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

stringValue.Equals(otherStringValue):

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

stringValue == otherStringValue:

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

Object.ReferenceEquals(stringValue, otherStringValue):

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


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

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

Ответ 2

Из MSDN:

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

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

Ответ 3

Если вам когда-либо нравятся различия в методах 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

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

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

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

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

Ответ 4

Как Ed сказал, 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;

Ответ 5

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


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

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

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

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

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


String.CompareTo Method (String)

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

Использование:

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

Таким образом,

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

Метод String.Compare

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

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

Метод String.Equals

Преодоление класса объекта и перегрузка для безопасности типов. Учет по умолчанию: ординал. Обратите внимание:

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


Класс StringComparer

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

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

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

Одна большая разница в примечании .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");

Ответ 9

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

Ответ 10

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 );

Ответ 11

с .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 игнорировать случай и т.д., Но у меня нет времени смотреть сейчас. Как уже указывали другие, это будет сделано для сортировки. Сравнение для равенства таким образом приведет к ненужным накладным расходам.

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