Методы строк
С чеком в кассе можно сделать многое: найти на нём строчку с хлебом, перепечатать заголовок крупными буквами, отрезать нижнюю часть с рекламой. Но сам чек кассир не правит. Он печатает новый, уже с нужными изменениями, а старый остаётся таким, каким был.
У строки для таких действий есть готовые методы. Их вызывают через точку после строки, как Length, только со скобками в конце: raw.Trim(). Каждый метод возвращает результат: новую строку, число или bool. Исходная строка при этом остаётся прежней:
string raw = " Hello, World ";
string text = raw.Trim();
Console.WriteLine(text); // Hello, World
Console.WriteLine(text.ToUpper()); // HELLO, WORLD
Console.WriteLine(text.ToLower()); // hello, world
Console.WriteLine(raw.Length); // 16
Console.WriteLine(text.Length); // 12Давайте разберём пример по строкам:
raw.Trim()возвращает копию строки без пробелов по краям, и её кладут вtext.text.ToUpper()возвращает тот же текст заглавными буквами.text.ToLower()возвращает его строчными буквами.raw.Lengthпо-прежнему16:Trimне тронулraw, пробелы по краям остались в нём.- В
text12 символов:Trimне убирает пробел между словами.
Регистр и пробелы
ToUpper и ToLower
ToUpper переводит все буквы в заглавные, а ToLower — в строчные. Цифры, пробелы и знаки препинания они не меняют. Эти методы пригодятся, когда текст нужно привести к одному виду, например перед печатью заголовка.
Trim
Trim убирает пробелы, табуляции и переводы строки в начале и в конце строки. Внутри строки он ничего не трогает. Если лишние пробелы мешают только с одной стороны, есть TrimStart для начала и TrimEnd для конца.
Поиск
IndexOf
IndexOf ищет символ или кусок текста и возвращает индекс первого совпадения. Для text из примера text.IndexOf("World") даёт 7, а text.IndexOf('o') — 4: первая o стоит в слове Hello. Если совпадения нет, метод возвращает -1, как Array.IndexOf у массива.
Поиск учитывает регистр, поэтому text.IndexOf("world") тоже даёт -1.
Contains
Contains отвечает на вопрос попроще: есть ли кусок в строке вообще. text.Contains("World") возвращает true, а text.Contains("world") — false.
Вырезать кусок
Substring возвращает часть строки. У него две формы:
Substring(start)— от индексаstartдо конца строки;Substring(start, length)— кусок длинойlength, начиная с индексаstart.
Часто их сочетают с IndexOf: сначала находят границу, потом вырезают. Так из адреса почты достают имя и домен:
string email = "anna@mail.com";
int at = email.IndexOf('@');
Console.WriteLine(at); // 4
Console.WriteLine(email.Substring(0, at)); // anna
Console.WriteLine(email.Substring(at + 1)); // mail.com
Console.WriteLine(email.Substring(5, 4)); // mail
Console.WriteLine(email.IndexOf('#')); // -1Разберём по шагам:
@стоит на индексе4, это значение попадает вat.Substring(0, at)берёт четыре символа с начала:anna.Substring(at + 1)берёт всё после@:mail.com.Substring(5, 4)— четыре символа, начиная с индекса5:mail. Второе число — длина куска, а не индекс конца.- Символа
#в адресе нет, поэтомуIndexOfвозвращает-1.
Здесь чек и строка расходятся. Отрезанный кусок чека из него пропадает, а Substring ничего не отрезает: он копирует часть символов в новую строку, и email остаётся целым.
Кусок может заканчиваться последним символом строки: начало плюс длина могут равняться длине строки. Если сумма больше, Substring останавливает программу с исключением ArgumentOutOfRangeException.
На собеседовании любят спросить, что значит второй аргумент Substring. В C# это длина куска, а у похожего метода в Java и JavaScript — индекс конца. Те, кто пришёл с этих языков, часто путаются.
Заменить
Replace заменяет каждое вхождение одного куска на другой и возвращает новую строку. text.Replace("World", "C#") даёт Hello, C#, а text.Replace('l', 'L') меняет все три буквы: HeLLo, WorLd.
Разбить и собрать
Split
Split режет строку по символу-разделителю и возвращает массив кусков string[]. Сам разделитель в куски не попадает. Два разделителя подряд дают пустой кусок: "a,,b".Split(',') возвращает три строки, и средняя из них — пустая строка "".
string.Join
string.Join вы уже встречали в теме о массивах. Он делает обратное: склеивает элементы массива в одну строку и вставляет между ними разделитель. Этот метод вызывают у самого типа string, а не у конкретной строки: string.Join(", ", parts).
string line = "red,green,blue";
string[] parts = line.Split(',');
Console.WriteLine(parts.Length); // 3
Console.WriteLine(parts[1]); // green
Console.WriteLine(string.Join(" | ", parts)); // red | green | blueSplit(',') дал массив из трёх строк, и parts[1] — вторая из них. string.Join склеил их обратно, но уже через |.
Частая ошибка
Второе число Substring приняли за индекс конца:
string text = "Hello, World";
Console.WriteLine(text.Substring(7, 12)); // ✗Unhandled exception. System.ArgumentOutOfRangeException: Index and length must refer to a location within the string. (Parameter 'length')Хотели вырезать World: он начинается на индексе 7, а строка кончается перед индексом 12. Но Substring прочитал второе число как длину: 12 символов, начиная с индекса 7. В строке всего 12 символов, и такой кусок вышел бы за её конец.
Программа компилируется, а при запуске останавливается на этой строке. Нужен кусок длиной 5, text.Substring(7, 5), или остаток строки, text.Substring(7).
Главное
- Методы строки возвращают результат, а исходная строка остаётся прежней:
Trim,ToUpper,ToLower,Replaceдают новые строки. IndexOfвозвращает индекс первого совпадения или-1,Contains—trueилиfalse; оба учитывают регистр.Substring(start, length)берётlengthсимволов, начиная соstart; второе число — длина, а не индекс конца.Splitрежет строку в массив по разделителю,string.Joinсклеивает массив обратно.