У System.String десятки методов. На этой странице описаны те, что выполняют большую часть работы в реальном коде, с важными опциями и ловушками. Для всех них действует одно правило: строки неизменяемы, поэтому каждый метод возвращает новую строку (или значение) и не меняет исходную. s.Trim(); в отдельной строке ничего не делает; пишите s = s.Trim();.
Split
Split разбивает строку на string[] по каждому разделителю:
Вывод:
3
apple
banana
cherry
red/green/ blue/yellow
INFO/started/ready
Обратите внимание на " blue": Split режет точно по разделителю и сохраняет пробелы. Две опции решают частые задачи очистки:
Вывод:
5
4
c#|dotnet|linq
key=[Subject] value=[Re: Meeting: Friday]
3
RemoveEmptyEntries убирает части нулевой длины, но не части, состоящие только из пробелов (" " выше уцелела). .NET 5 добавил StringSplitOptions.TrimEntries, и эти опции можно сочетать: tags.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) даёт чистый результат одним вызовом. Если передать null в качестве разделителя, строка разделится по любым пробельным символам; это обычный способ разбить текст на слова.
Для разделения по одному char (Split(',')) массив не нужен. Перегрузки, которые принимают char вместе с опциями или одну string, есть начиная с .NET Core 2.0; формы с массивом, использованные выше, работают везде, включая .NET Framework и Unity.
Replace
Replace заменяет каждое вхождение символа или подстроки:
Вывод:
5551234567
555.123.4567
Cats and dogs and CATS
dogs and dogs and dogs
dogs and cats and CATS
too many spaces
Перегрузка с аргументом StringComparison доступна в .NET Core 2.0 и новее. В .NET Framework замена без учёта регистра выполняется через Regex.Replace(text, Regex.Escape(find), replacement, RegexOptions.IgnoreCase). Замена на "" это способ удалить символы, а цепочка из нескольких вызовов Replace вполне годится для нескольких подстановок.
Contains, IndexOf, StartsWith и EndsWith
Эти методы выполняют поиск. Contains отвечает да или нет; IndexOf и LastIndexOf возвращают позицию или -1, если совпадения нет; StartsWith и EndsWith проверяют концы строки.
Вывод:
True
False
True
True
8
30
28
-1
16
False
True
True
Все они по умолчанию учитывают регистр. Contains(string, StringComparison) есть в .NET Core 2.1 и новее; форма IndexOf(...) >= 0 работает в любой версии, поэтому она встречается в старом коде. IndexOfAny(new[] { ',', ';' }) находит первый из нескольких символов.
Замечание о культуре: без StringComparison методы StartsWith, EndsWith, IndexOf(string) и CompareTo используют правила с учётом культуры, а Contains, Replace и IndexOf(char) сравнивают порядково. Явная передача StringComparison.Ordinal или OrdinalIgnoreCase убирает неоднозначность, и анализаторы кода это рекомендуют.
Trim, TrimStart и TrimEnd
Trim удаляет пробельные символы (пробелы, табуляции, переводы строк) с обоих концов. TrimStart и TrimEnd удаляют с одного конца. Если передать символы, удаляются они:
Вывод:
[ana@example.com]
[ana@example.com \n]
[ x]
SALE
7
path/to/dir
1,234.50
Trim затрагивает только концы; пробелы внутри строки сохраняются. TrimStart('0') для "000" возвращает пустую строку, поэтому строки с числами разбирайте через int.Parse, а не убирайте нули вручную.
ToUpper и ToLower
Вывод:
MAYA LOPEZ
maya lopez
MAYA LOPEZ
Coffee
ToUpper и ToLower следуют текущей культуре, поэтому в турецкой культуре "i".ToUpper() даёт заглавную İ с точкой, а не I. Для идентификаторов, ключей и имён файлов используйте ToUpperInvariant и ToLowerInvariant. Для сравнения используйте StringComparison вместо изменения регистра (см. строки). Чтобы сделать каждое слово с заглавной буквы, есть CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text), хотя он не трогает слова, которые уже целиком написаны заглавными.
PadLeft и PadRight
Дополнение добавляет символы, пока строка не достигнет заданной общей ширины. Это удобно для вывода фиксированной ширины и для дополнения кодов нулями:
Вывод:
000042
[Tea ]
[ Tea]
Too long already
Espresso.. 2.40
Latte..... 3.60
Mocha..... 3.95
Выравнивание в интерполяции ({name,-10}) делает то же самое прямо в строке.
Join и Concat
string.Join ставит разделитель между элементами любой коллекции. string.Concat соединяет без разделителя:
Вывод:
Ana, Ben, Chloe
1 + 2 + 3
True
2026-09
AnaBenChloe
Ana, Ben and Chloe
Join это правильный способ собрать список с разделителями: не остаётся лишнего разделителя в конце, который нужно удалять, и результат строится за один проход. Он вызывает ToString() у каждого элемента, поэтому работает и с числами, и с объектами.
Reverse, Insert и Remove
Метода string.Reverse, возвращающего строку, нет. Два обычных подхода:
Вывод:
desserts
desserts
True
2026/Q3-09
Hello
HelloWorld
word.Reverse() сам по себе возвращает IEnumerable<char>, а не строку; при выводе вы увидите имя типа. Оба способа переворачивают кодовые единицы UTF-16, что ломает символы из двух единиц (большинство эмодзи) и буквы с комбинируемыми диакритическими знаками.
Краткая справка
| Задача | Метод |
|---|---|
| Разбить на части | s.Split(','), s.Split(new[] {',', ';'}, StringSplitOptions.RemoveEmptyEntries) |
| Заменить все | s.Replace("a", "b") |
| Содержит | s.Contains("x"), s.Contains("x", StringComparison.OrdinalIgnoreCase) |
| Позиция | s.IndexOf("x"), s.LastIndexOf('x') (-1, если нет) |
| Начинается или заканчивается на | s.StartsWith("x"), s.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase) |
| Убрать пробелы по краям | s.Trim(), s.TrimStart(), s.TrimEnd() |
| Изменить регистр | s.ToUpper(), s.ToLowerInvariant() |
| Дополнить до ширины | s.PadLeft(6, '0'), s.PadRight(10) |
| Соединить коллекцию | string.Join(", ", items) |
| Часть строки | s.Substring(start, length) |
| Вставить или удалить | s.Insert(i, "x"), s.Remove(i, count) |
| Проверка на null или пустоту | string.IsNullOrWhiteSpace(s) |
Часто задаваемые вопросы
Как разделить строку в C#?
text.Split(',') возвращает string[] из частей между запятыми. Несколько разделителей передаются массивом (Split(new[] { ',', ';' })), строковый разделитель через Split(new[] { ", " }, StringSplitOptions.None), а StringSplitOptions.RemoveEmptyEntries убирает пустые части, возникающие из-за сдвоенных разделителей. .NET 5 добавил StringSplitOptions.TrimEntries, чтобы обрезать пробелы у каждой части.
Как проверить, содержит ли строка другую строку без учёта регистра?
В .NET Core 2.1 и новее: text.Contains("error", StringComparison.OrdinalIgnoreCase). В .NET Framework, где такой перегрузки нет, используйте text.IndexOf("error", StringComparison.OrdinalIgnoreCase) >= 0. Избегайте text.ToLower().Contains(...): это создаёт копию и в некоторых культурах может работать неправильно.
Изменяет ли String.Replace исходную строку в C#?
Нет. Строки неизменяемы, поэтому Replace возвращает новую строку с заменой всех вхождений и оставляет исходную как была. Пишите s = s.Replace("old", "new");. Метод заменяет все вхождения, а не только первое; чтобы заменить только первое, найдите его через IndexOf и соберите строку заново или вызовите Replace у экземпляра Regex с количеством 1.
Что возвращает IndexOf, если строка не найдена?
-1. Любой результат 0 или больше это позиция первого совпадения, считая с нуля. Всегда проверяйте на -1, прежде чем использовать результат как индекс, потому что Substring(-1) выбрасывает исключение, а Substring(-1 + 1) молча возвращает всю строку. LastIndexOf работает так же, но ищет с конца.
Как перевернуть строку в C#?
Скопируйте её в массив символов, переверните массив и создайте новую строку: char[] a = s.ToCharArray(); Array.Reverse(a); string r = new string(a);. С LINQ то же делает new string(s.Reverse().ToArray()). Оба способа переворачивают единицы UTF-16, поэтому эмодзи и комбинируемые диакритические знаки могут перемешаться.