string в C# это последовательность символов UTF-16 (значений char). Это ссылочный тип, но в важных отношениях он ведёт себя как значение: он неизменяемый, а == сравнивает текст, а не идентичность объектов. string это ключевое слово C# для типа .NET System.String; они взаимозаменяемы.
Вывод:
Porto
5
0
*****
hi
Porto has 5 letters
Строки неизменяемы
Ни один метод не изменяет строку на месте. ToUpper, Replace, Trim и все остальные методы возвращают новую строку и не трогают исходную. Забыть использовать возвращаемое значение очень частая ошибка при работе со строками:
Вывод:
[ maya ]
[MAYA]
tea
tea and cake
Неизменяемость делает строки безопасными для совместного использования между потоками и для использования в качестве ключей словаря. Цена в том, что сборка строки по частям в цикле создаёт новую строку на каждом шаге; для этого используйте StringBuilder.
Длина и индексация
Length это свойство (без скобок). Индексатор s[i] возвращает char в позиции i, считая с 0, и доступен только для чтения:
Вывод:
7
A
1
IndexOutOfRangeException
XB-2931
C# 8 и новее принимают также индекс с конца: code[^1] это последний символ, то же самое, что code[code.Length - 1]. Чтобы взять несколько символов сразу, см. подстроки.
Length считает кодовые единицы UTF-16, а не то, что читатель видит как символы. Большинство букв в большинстве языков занимают одну единицу, но эмодзи и некоторые редкие письменности используют две (суррогатную пару), поэтому "👍".Length равно 2.
Сравнение строк
== и != сравнивают символы с учётом регистра. Во всех остальных случаях передавайте значение StringComparison, которое говорит, как сравнивать:
Вывод:
False
False
True
True
apple first
True
False
False
True
Какое сравнение использовать:
Ordinalсравнивает числовые коды символов. Он быстрый, предсказуемый и одинаковый на любой машине. Используйте его для идентификаторов, имён файлов, ключей, значений протоколов и всего, что не показывается человеку.OrdinalIgnoreCaseто же самое, но без учёта регистра. Правильный выбор для проверок без учёта регистра, например расширений файлов или HTTP-заголовков.CurrentCulture(иCurrentCultureIgnoreCase) следует правилам языка пользователя, поэтому сортирует слова так, как это сделал бы словарь этого языка. Используйте его для сортировки списков, которые видят пользователи.InvariantCultureиспользует правила с учётом культуры, которые не зависят от языковых настроек пользователя. Он всё равно зависит от библиотеки глобализации: современный .NET использует ICU, .NET Framework использует NLS Windows, и они могут по-разному упорядочивать некоторые строки.
string.Compare(a, b) и a.CompareTo(b) без StringComparison используют текущую культуру, поэтому их результаты различаются на разных машинах. Не сравнивайте через a.ToLower() == b.ToLower(): это создаёт две новые строки и в некоторых культурах даёт неверные ответы (классический случай турецкие i с точкой и без точки).
Вызов a.Equals(b), когда a равно null, выбрасывает NullReferenceException, тогда как a == b и статический string.Equals(a, b) безопасно обрабатывают null.
Escape-последовательности
Внутри обычного строкового литерала обратный слеш начинает escape-последовательность:
| Последовательность | Значение |
|---|---|
\n | Перевод строки (line feed) |
\r | Возврат каретки |
\t | Табуляция |
\\ | Обратный слеш |
\" | Двойная кавычка |
\' | Одинарная кавычка (нужна только в литерале char) |
\0 | Нулевой символ |
\uXXXX | Символ UTF-16 по 4-значному шестнадцатеричному коду, например \u00e9 |
\U0001F44D | Символ по 8-значному шестнадцатеричному коду; выше U+FFFF превращается в два значения char |
\xH to \xHHHH | Символ по 1 до 4 шестнадцатеричных цифр (избегайте: длина неоднозначна) |
\a, \b, \f, \v | Звуковой сигнал, возврат на символ, перевод страницы, вертикальная табуляция |
\e | Символ escape, U+001B (C# 13) |
Вывод:
Name: Ana
City: Porto
She said "hi"
C:\temp\report.txt
cafe = cafe
' is a quote char
Нераспознанная последовательность, например "\d", это ошибка компиляции (CS1009, unrecognized escape sequence), и именно это происходит, когда путь Windows или регулярное выражение записаны как обычная строка.
Verbatim-строки и многострочные строки
Префикс @ перед литералом делает его verbatim (буквальным): обратные слеши становятся обычными символами, а строка может занимать несколько строк. Остаётся только одно экранирование "", которое даёт одну двойную кавычку.
Вывод:
C:\Users\ana\Documents\notes.txt
\d{3}-\d{4}
He said "ready" and left.
Rua das Flores 12
4050-262 Porto
Portugal
first line
second line
Многострочная verbatim-строка включает всё между кавычками, в том числе отступы строк продолжения, поэтому такие строки обычно пишут вплотную к левому краю, как выше. Переводы строк в ней те же, что в исходном файле, поэтому файл, сохранённый с окончаниями строк Windows, даёт \r\n.
C# 11 добавил необработанные строковые литералы (raw string literals), которые решают обе проблемы. Они начинаются и заканчиваются тремя или более двойными кавычками, вообще не требуют экранирования и убирают отступ, равный отступу закрывающих кавычек:
// C# 11 and later
string json = """
{
"name": "Ana",
"path": "C:\temp"
}
""";
// The 4 spaces before the closing """ are removed from every line.
Если само содержимое содержит """, начинайте и заканчивайте четырьмя кавычками. Необработанные литералы сочетаются и с интерполяцией ($"""..."""); см. интерполяция строк.
null, пустая строка и пробелы
Строковая переменная может быть null (строки нет вообще), пустой ("", длина 0) или содержать только пробельные символы. Два статических метода проверяют эти случаи без риска получить NullReferenceException:
Вывод:
null empty: True blank: True
"" empty: True blank: True
" " empty: False blank: True
"Ana" empty: False blank: False
True
Для проверки пользовательского ввода почти всегда нужен string.IsNullOrWhiteSpace. string.Empty и "" это одно и то же значение; что писать, дело стиля.
Перебор символов
Строка перечисляема, поэтому foreach проходит по каждому char. У типа char есть статические методы для классификации символов:
Вывод:
letters=6 digits=4 upper=1 symbols=1
!6202tesnuS
Соединение строк
+ выполняет конкатенацию и работает с любым типом с другой стороны (вызывая ToString()). Для объединения многих значений лучше подходит интерполяция или string.Join:
Вывод:
Ana Silva, 31
Ana Silva, 31
AnaSilva
tea | coffee | juice
Total: 23
Total: 5
Последние две строки показывают ловушку приоритета: + вычисляется слева направо, поэтому как только левая часть стала строкой, каждый следующий + это конкатенация. Заключайте арифметику внутри конкатенации в скобки.
Часто задаваемые вопросы
Как узнать длину строки в C#?
Используйте свойство Length: "hello".Length равно 5. Это свойство, а не метод, поэтому скобки не нужны. Length считает кодовые единицы UTF-16, поэтому эмодзи или другой символ за пределами базовой многоязычной плоскости считается за 2. Обращение к нему у строки null выбрасывает NullReferenceException.
Как сравнивать строки в C#?
a == b сравнивает текст с учётом регистра. Для сравнения без учёта регистра используйте string.Equals(a, b, StringComparison.OrdinalIgnoreCase). Чтобы сортировать или упорядочивать строки, используйте string.Compare(a, b, StringComparison.Ordinal) или сравнение с учётом культуры, которое возвращает отрицательное число, ноль или положительное число.
Как написать многострочную строку в C#?
Поставьте перед литералом @, чтобы сделать его verbatim: он может занимать несколько строк, обратные слеши в нём буквальные, а двойная кавычка записывается как "". В C# 11 и новее необработанные строковые литералы, ограниченные """, тоже занимают несколько строк, убирают общий отступ и вообще не требуют экранирования. Можно также соединять строки через \n или Environment.NewLine.
Что такое verbatim-строка в C#?
Строковый литерал с префиксом @, например @"C:\Users\ana". Escape-последовательности в нём не обрабатываются, поэтому обратный слеш это просто обратный слеш, что делает такую строку естественным выбором для путей Windows и регулярных выражений. Единственное экранирование внутри неё "" для двойной кавычки.
Чем string отличается от String в C#?
Ничем. string это ключевое слово C#, псевдоним типа .NET System.String, так же как int это псевдоним System.Int32. По соглашению string используют в объявлениях и в статических вызовах вроде string.IsNullOrEmpty(...), но оба варианта компилируются в одно и то же.
Какие escape-последовательности поддерживает C#?
\n перевод строки, \r возврат каретки, \t табуляция, \\ обратный слеш, \" двойная кавычка, \' одинарная кавычка, \0 нулевой символ, \uXXXX символ UTF-16 по шестнадцатеричному коду, \U0001F600 символ по 8-значному коду (превращается в суррогатную пару), \a звуковой сигнал, \b возврат на символ, \f перевод страницы, \v вертикальная табуляция и \e (C# 13) символ escape. Неизвестная последовательность, например \d, это ошибка компиляции (CS1009), поэтому регулярные выражения обычно пишут как verbatim-строки.