Сравнение строк
Возьмите два чека из одного магазина за одну и ту же покупку. Это два разных листка бумаги, но напечатано на них одно и то же. Одинаковые ли это чеки? Всё зависит от вопроса: «это один листок?» или «на них один текст?».
Для строк C# отвечает на второй вопрос. Оператор == сравнивает текст, символ за символом, даже когда строки — два разных объекта:
string a = "cat";
string b = "CAT".ToLower();
Console.WriteLine(a == b); // True
Console.WriteLine(a == "Cat"); // False
Console.WriteLine(a != "dog"); // TrueДавайте разберём пример по строкам:
"CAT".ToLower()создаёт при запуске новую строку"cat". В памяти теперь две строки с одинаковым текстом, как два листка с одинаковой покупкой.a == bсравнивает их посимвольно и печатаетTrue.a == "Cat"печатаетFalse:'c'и'C'— разные символы, и регистр букв важен.!=даёт обратный ответ: строка"cat"не равна"dog", поэтому печатаетсяTrue.
== сравнивает текст
Для массивов == проверяет, один ли это массив, и два массива с одинаковыми элементами не равны. У строк == устроен иначе: он сравнивает длину и затем каждый символ. Поэтому строки с одинаковым текстом равны, откуда бы они ни взялись.
Здесь картинка с чеками неточна. Две строки с одинаковым текстом иногда оказываются одним объектом: одинаковые литералы, как вы видели, хранятся как одна строка. Для == это неважно: он сравнивает текст в любом случае.
Этот вопрос часто задают на собеседовании: что сравнивает == у строк? В C# — текст, хотя string и ссылочный тип. А в Java == для строк сравнивает ссылки, так что ответ зависит от языка.
Без учёта регистра
Пользователь ответил YES, а программа ждёт yes. По смыслу ответы одинаковые, но == их различает. Для сравнения без учёта регистра у строки есть метод Equals со вторым аргументом — способом сравнения:
string answer = "YES";
Console.WriteLine(answer == "yes"); // False
Console.WriteLine(answer.Equals("yes", StringComparison.OrdinalIgnoreCase)); // TrueStringComparison.OrdinalIgnoreCase
Название способа складывается из двух частей:
Ordinal— сравнивать символ с символом как есть, без правил какого-либо языка;IgnoreCase— считать заглавную и строчную букву одинаковыми.
Тот же способ сравнения можно передать и в string.Equals(answer, "yes", StringComparison.OrdinalIgnoreCase): там обе строки идут аргументами.
Почему не ToLower
Можно привести обе строки к строчным буквам: answer.ToLower() == "yes". Это тоже работает, но у такого способа два минуса:
- каждый
ToLowerсоздаёт новую строку, хотя нужен только ответtrueилиfalse; ToLowerиToUpperследуют региональным настройкам компьютера. С турецкими настройками"TITLE".ToLower()даёт"tıtle"с буквойıбез точки, и сравнение с"title"вернётfalse.
OrdinalIgnoreCase от настроек не зависит и новых строк не создаёт.
Пустая строка
Пустая строка "" — строка без символов, её длина 0. Проверить, пуста ли строка, можно сравнением s == "" или через s.Length == 0. Чаще пишут string.IsNullOrEmpty(s): этот метод возвращает true и для пустой строки, и для значения null, которое означает, что строки нет вовсе.
Пробел тоже символ, поэтому строка " " не пустая. Если строку из одних пробелов нужно считать пустой, есть string.IsNullOrWhiteSpace:
string empty = "";
string space = " ";
Console.WriteLine(empty.Length); // 0
Console.WriteLine(string.IsNullOrEmpty(empty)); // True
Console.WriteLine(string.IsNullOrEmpty(space)); // False
Console.WriteLine(string.IsNullOrWhiteSpace(space)); // TrueЧастая ошибка
Строки попробовали сравнить по алфавиту знаком <:
string a = "apple";
string b = "banana";
Console.WriteLine(a < b); // ✗error CS0019: Operator '<' cannot be applied to operands of type 'string' and 'string'Программа не компилируется: операторы < и > работают с числами и символами, а со строками — нет. Порядок строк узнают через string.Compare(a, b). Метод возвращает:
- отрицательное число, если
aстоит по алфавиту раньшеb; - ноль для равных строк;
- положительное число, если
aстоит позже.
Здесь string.Compare(a, b) < 0 даёт true.
Главное
==и!=сравнивают текст строк посимвольно и с учётом регистра, даже если это два разных объекта.- Без учёта регистра сравнивают через
EqualsсоStringComparison.OrdinalIgnoreCase, а не черезToLower. string.IsNullOrEmptyпроверяет пустую строку иnull, аstring.IsNullOrWhiteSpaceещё и строку из пробелов.<и>для строк не компилируются; порядок по алфавиту даётstring.Compare.