Тема работы со строками является одной из значимых при изучении любого языка программирования. В приведенном материале будут рассмотрены как базовые концепции работы со строками, так и расширенные возможности, предоставляемые C#.
- Знакомство со строками в C#
- Создание и инициализация объекта класса String
- Базовый API для работы со строками
- Форматирование строк
- $ — интерполяция строк
- Управляющие символы (литералы)
- @ – буквальный идентификатор
- Класс StringBuilder
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.
Знакомство со строками в C#
За представление строк в C# отвечает класс System.String. В коде, для объявления переменной соответствующего типа, предпочтительно использовать следующий вариант написания: string – с маленькой буквы. Это ключевое слово языка, используя которое можно объявлять строковые переменные, также как int является псевдонимом для System.Int32, а bool – для System.Boolean.
string s1 = "Hello, World!"; Console.WriteLine(s1);
Допустимо объявление строковых переменных через ключевое слово var:
var s2 = "Create by var"; Console.WriteLine(s2);
Для объединения строк используется оператор +:
string s3 = "Hello, "; string s4 = s3 + "John!"; Console.WriteLine(s4);
При работе со String следует помнить, что при переопределении значения переменной создается новый экземпляр строковой переменной в памяти. Поэтому, если вам нужно собрать строку из большого количества составляющих, то использование оператора + не самый лучший вариант. В этом случае будет происходить перерасход памяти: при выполнении операции объединения с присваиванием для очень большого количества подстрок, приложение может аварийно завершиться из-за того, что сборщик мусора не будет успевать удалять неиспользуемые объекты, а новые будут продолжать появляться с большой скоростью. Для решения этой задачи используйте StringBuilder, о нем будет рассказано в конце этого урока.
Создание и инициализация объекта класса String
Существует несколько способов создать объект класса String и проинициализировать его. Рассмотрим варианты, которые доступны в C#. Наиболее распространенный способ сделать эту операцию – это присвоить строковое значение переменной без явного вызова конструктора, так, как мы это делали в предыдущем разделе:
string s5 = "test1"; var s6 = "test2";
Для дословного представления строки, для того чтобы проигнорировать управляющие последовательности, используйте префикс @ перед значением. Сравните вывод следующей конструкции:
Console.WriteLine("first line\nSecond line");
С вариантом:
Console.WriteLine(@"first line\nSecond line");
Если требуется подготовить строковое значение с использованием набора переменных, то можно воспользоваться статическим методом Format класса String, либо префиксом $:
int age = 27; Console.WriteLine(String.Format("Age: {0}", age)); Console.WriteLine(""); Console.WriteLine($"Age: {age}"); Console.WriteLine("");
Можно явно вызвать конструктор типа c передачей в него параметров. Самый простой вариант – это передать строку:
string s7 = new string("test3");
В качестве параметра может выступать массив Char элементов:
char[] charArray = {'H', 'e', 'l', 'l', 'o'}; string s8 = new string(charArray);
Ещё вариант – это указать элемент типа char и количество раз, которое его нужно повторить:
string s9 = new string('O', 10); // "OOOOOOOOOO"
Для создания строки также можно использовать указатели на Char* и SByte*, но в данном уроке эта тема рассматриваться не будет.
Базовый API для работы со строками
В рамках данного раздела рассмотрим наиболее интересные и полезные методы и свойства класса String.
Объединение строк. Оператор +, методы Concat и Join
Сцеплять строки между собой можно с помощью оператора +, при этом, в результате объединения, будет создан новый объект:
string s10 = "Area"; string s11 = " 51"; Console.WriteLine("Concat by +: " + s10 + s11);
В составе API, который предоставляет System.String, есть метод Concat, который может выполнять ту же работу:
Console.WriteLine("Concat by Concat(): " + string.Concat(s10, s11));
Метод Concat позволяет объединить до четырех строк через прямое перечисление. Если нужно таким образом объединить больше строковых переменных и значений, то используйте оператор +. Полезным свойством Concat является то, что он может принять на вход массив элементов типа String и объединить их:
string[] sArr1 = {"First ", "Second ", "Third "}; Console.WriteLine(string.Concat(sArr1));
Для объединения элементов с указанием разделителя используется метод Join. В предыдущем примере, элементы в массиве sArr1 уже содержали пробел, это не всегда удобно, решим задачу объединения элементов, которые не содержат разделителей, с помощью Join:
string[] sArr2 = {"First", "Second", "Third"}; Console.WriteLine("Join elements in array by Join() with space: " + string.Join(" ", sArr2));
В качестве разделителя можно использовать любую строку:
Console.WriteLine("Join elements in array by Join() with <->: " + string.Join("<->", sArr2));
Поиск и извлечение элементов из строки. Оператор [], методы IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny, Substring
Для получения символа из строки с конкретной позиции можно использовать синтаксис подобный тому, что применяется при работе с массивами – через квадратные скобки []:
string s12 = "Hello"; Console.WriteLine("Get element by index s12[3]: " + s12[3]);
Для решения обратной задачи: поиск индекса первого (последнего) вхождения элемента или сроки в данной строке используются методы IndexOf, IndexOfAny и LastIndexOf, LastIndexOfAny.
В таблице ниже перечислены некоторые из предоставляемых System.String вариантов этих методов.
Метод |
Описание |
IndexOf(Char) |
Возвращает индекс первого вхождения символа. |
IndexOf(Char, Int32) |
Возвращает индекс первого вхождения символа начиная с заданной позиции. |
IndexOf(Char, Int32, Int32) |
Возвращает индекс первого вхождения символа начиная с заданной позиции, проверяется указанное количество элементов. |
IndexOf(String) |
Назначение методов совпадает с перечисленными выше, но поиск выполняется для строки. |
IndexOfAny(Char[]) |
Назначение методов совпадает с перечисленными выше, но выполняется поиск индекса первого вхождения любого из переданных в массиве элементов. |
LastIndexOf([Char | String]) |
Возвращает индекс последнего вхождения символа или строки. Можно задавать индекс, с которого начинать поиск и количество проверяемых позиций. [Char | String] – означает Char или String |
LastIndexOfAny(Char[]) |
Возвращает индекс последнего вхождения любого из переданных в массиве элементов.Можно задавать индекс с которого начинать поиск и количество проверяемых позиций |
// s1 = "Hello, World!" // Поиск первого вхождения символа 'r' Console.WriteLine("Index of \'r\': " + s1.IndexOf('r')); // Поиск первого вхождения символа 'l' начиная с позиции 4 Console.WriteLine("Index of \'l\', start at 4: " + s1.IndexOf('l', 4)); // Поиск первого вхождения строки "World" Console.WriteLine("Index of \"World\": " + s1.IndexOf("World")); // Поиск первого вхождения символа из набора ['o', 'd', ','] Console.WriteLine("Index of pos of any symbol in array: " + s1.IndexOfAny(new char[] {'o', 'd', ','})); // Поиск последнего вхождения символа 'l' Console.WriteLine("Last index of \'l\': " + s1.LastIndexOf('l')); // Поиск последнего вхождения строки "or" Console.WriteLine("Last index of \"or\": " + s1.LastIndexOf("or")); // Поиск последнего вхождения символа из набора ['o', 'd', ','] Console.WriteLine("Last index of pos of any symbol in array: " + s1.LastIndexOfAny(new char[] {'o', 'd', ','}));
Для определения того, содержит ли данная строка указанную подстроку, а также для проверки равенства начала или конца строки заданному значению используйте методы: Contains, StartsWith и EndsWith.
Метод |
Описание |
Contains(Char) |
Возвращает True если строка содержит указанный символ или подстроки. |
StartsWith(Char) |
Возвращает True если строка начинается с заданного символа или подстроки. |
EndsWith(Char) |
Возвращает True если строка заканчивается на заданный символ или подстроку. |
Console.WriteLine("Contains \"World\"? " + s1.Contains("World")); // True Console.WriteLine("Starts with \"He\"? " + s1.StartsWith("He")); // True Console.WriteLine("Ends with \"ld\"? " + s1.EndsWith("ld")); // False
Задачу извлечения подстроки из данной строки решает метод SubString:
Метод |
Описание |
Substring(Int32) |
Возвращает подстроку начиная с указанной позиции и до конца исходной строки. |
Substring(Int32, Int32) |
Возвращает подстроку начиная с указанной позиции с заданной длины. |
Console.WriteLine("Substring start at pos 7: " + s1.Substring(7)); // World! Console.WriteLine("Substring start at pos 7 (4 chars): " + s1.Substring(7, 4)); // Worl
Сравнение срок
Для сравнения строк можно использовать оператор сравнения ==, при этом будут сравниваться значения строковых переменных, а не их ссылки, как это делается для других ссылочных типов.
string t1 = "John"; string t2 = "John"; string t3 = "Mary"; Console.WriteLine("t1 == t2: " + (t1 == t2)); // True Console.WriteLine("t1 != t2: " + (t1 != t2)); // False Console.WriteLine("t1 == t3: " + (t1 == t3)); // False
Для сравнения также можно использовать метод Equals, но это менее удобный вариант:
Console.WriteLine("Equals method: t1.Equals(t2)" + t1.Equals(t2)); // True Console.WriteLine("Equals method: t1.Equals(t3)" + t1.Equals(t3)); // False
Модификация срок
Класс String предоставляет довольно большое количество инструментов для изменения строк.
Вставка строки в исходную в заданную позицию осуществляется с помощью метода Insert:
Console.WriteLine("Insert: " + "26".Insert(1, "[4]")); // 2[4]6
Для приведения строки к заданной длине с выравниванием по левому (правому) краю с заполнением недостающих символов пробелами используются методы PadLeft и PadRight:
Console.WriteLine("PadLeft: "); Console.WriteLine("some string".PadLeft(15)); // " some string" Console.WriteLine("some string".PadLeft(15, '*')); // "****some string" Console.WriteLine("PadRight: "); Console.WriteLine("some string".PadRight(15)); // "some string " Console.WriteLine("some string".PadRight(15, '*')); // "some string****"
Метод Remove удаляет подстроку из исходной строки. Возможны два варианта использования:
Метод |
Описание |
Remove(Int32) |
Удаляет все символы начиная с заданного и до конца строки. |
Remove(Int32, Int32) |
Удаляет с указанной позиции заданное число символов. |
Console.WriteLine("Remove demo1: " + "Hello".Remove(2)); Console.WriteLine("Remove demo2: " + "Hello".Remove(2, 2));
Замена элементов строки производится с помощью метода Replace. Наиболее часто используемые варианты – это замена символа на символ и строки на подстроку:
Console.WriteLine("Hello, World!".Replace('!', '.')); // Hello, World. Console.WriteLine("Hello, World!".Replace("World", "John")); // Hello, John!
Для преобразования строки к верхнему регистру используйте метод ToUpper(), к нижнему – ToLower():
Console.WriteLine("Hello, World!".ToUpper()); // HELLO, WORLD! Console.WriteLine("Hello, World!".ToLower()); // hello, world!
За удаление начальных и конечных символов отвечают методы, начинающиеся на Trim (см. таблицу ниже).
Метод |
Описание |
Trim() |
Удаляет символы пробелы из начала и конца строки. |
Trim(Char) |
Удаляет экземпляры символа из начала и конца строки. |
Trim(Char[]) |
Удаляет экземпляры символов из начала и конца строки. |
TrimStart() |
Удаляет экземпляры символов из начала строки. |
TrimEnd() |
Удаляет экземпляры символов из конца строки. |
Console.WriteLine(" hello ".Trim()); // "hello" Console.WriteLine("***hello---".Trim('*')); // "hello---" Console.WriteLine("***hello---".Trim(new char[] {'*', '-'})); // "hello" Console.WriteLine(" hello ".TrimStart()); // "hello " Console.WriteLine(" hello ".TrimEnd()); // " hello"
Методы и свойства общего назначения
Рассмотрим некоторые из полезных методов и свойств, которые не вошли в приведенные выше группы.
System.Length – возвращает длину строки:
Console.WriteLine("Hello".Length); // 5
System.Split() – разделяет заданную строку на подстроки, в качестве разделителя используется указанный через параметр символ (или группа символов):
foreach(var s in "1 2 3".Split(' ')) Console.WriteLine(s); foreach(var s in "1 2 3-4-5-6".Split(new char[]{' ', '-'})) Console.WriteLine(s);
System.Empty – возвращает пустую строку.
Форматирование строк
Под форматированием строк, в рамках данного раздела, понимается встраивание в строку различных элементом (число, дата и т.п.), представленных в заданном формате. Форматирование можно осуществлять с помощью метода ToString с передачей в него нужных описателей, метода Format, который, в качестве аргументов, получает строку со специальными вставками, определяющими представление элементов и непосредственно сами элементы.
Для начала рассмотрим на нескольких примерах работу с этими методоми:
// ToString Console.WriteLine(12345.ToString("X")); // String.Format Console.WriteLine(string.Format("value: {0}", 1.23456)); Console.WriteLine(string.Format("value: {0:F}", 1.23456)); Console.WriteLine(string.Format("value: {0:d}", 1.23456)); // WriteLine без использования String.Format Console.WriteLine("value: {0}", 1.23456); // 1,23456 Console.WriteLine("value: {0:F}", 1.23456); // 1.235 Console.WriteLine("date: {0:d}", DateTime.Now); // 07.09.2020
Эта функциональность также доступна для методов StringBuilder.AppendFormat, TextWriter.WriteLine, Debug.WriteLine, методов из Trace, которые выводят текстовые сообщения, например: Trace.TraceError и метод TraceSource.TraceInformation.
Каждый элемент форматирования представляется следующим образом:
{index[,alignment][:formatString]}
где index – это индекс элемента, которым будет замещена данная конструкция;
alignment – выравнивание;
formatString – формат.
Ниже приведены примеры использования элементов форматирования:
Console.WriteLine("Only index: {0}", 123); // Only index: 123 Console.WriteLine("Index with alignment: {0,-5}{1,5}", 123, 456); // Index with alignment: 123 456 Console.WriteLine("Index with format: 0x{0:X}", 123); // Index with format: 0x7B
Представление чисел
Для представления чисел используются следующие описатели формата (список не полный, более детальную информацию можете найти в официальной документации):
Описатель формата |
Описание |
“C” или “c” |
Представление валюты. |
“D” или “d” |
Представление целого числа. |
“E” или “e” |
Представление числа в экспоненциальном виде. |
“F” или “f” |
Представление числа в формате с плавающей точкой. |
“P” или “p” |
Представление процентов, выводит число умноженное на 100 со знаком процента. |
“X” или “x” |
Шестнадцатеричное представление. |
“0” |
Заместитель нуля. |
“#” |
Заместитель цифры. |
“.” |
Разделитель целой и дробной части. |
Примеры использования описателей формата для чисел:
Console.WriteLine("C symbol: {0:C}", 123); // 123,00 ₽ Console.WriteLine("D symbol: {0:D5}", 123); // 00123 Console.WriteLine("E symbol: {0:E}", 123456789);// 1,234568E+008 Console.WriteLine("F symbol: {0:F2}", 123.4567);// 123,46 Console.WriteLine("P symbol: {0:P}", 0.123); // 123,46 Console.WriteLine("X symbol: 0x{0:X}", 567); // 0x237 Console.WriteLine("0 symbol: {0:000.00}", 12.6789);// 012,68 Console.WriteLine("# symbol: {0:##}", 14.6789); // 15
Представление даты и времени
Для представления даты и времени используются следующие описатели формата (список не полный, более детальную информацию можете найти в официальной документации):
Описатель формата |
Описание |
“d” |
Сокращенный формат даты |
“D” |
Полный формат даты |
“f”, “F” |
Полный формат даты и времени с коротким (полным) форматом времени |
“g”, “G” |
Общий формат даты и времени с коротким (полным) форматом времени |
“t” |
Короткий формат времени |
“T” |
Полный формат времени |
“M”, “m” |
Шаблон дней месяца. |
“Y”, “y” |
Шаблон месяца года. |
Примеры использования описателей формата для даты и времени:
Console.WriteLine("d symbol: {0:d}", DateTime.Now); Console.WriteLine("D symbol: {0:D}", DateTime.Now); Console.WriteLine("f symbol: {0:f}", DateTime.Now); Console.WriteLine("F symbol: {0:F}", DateTime.Now); Console.WriteLine("g symbol: {0:g}", DateTime.Now); Console.WriteLine("G symbol: {0:G}", DateTime.Now); Console.WriteLine("t symbol: {0:t}", DateTime.Now); Console.WriteLine("T symbol: {0:T}", DateTime.Now); Console.WriteLine("{0:yyyy-MM-dd}", DateTime.Now); Console.WriteLine("{0:dd/MM/yy}", DateTime.Now); Console.WriteLine("{0:dd/MM/yy HH:mm:ss}", DateTime.Now);
$ — интерполяция строк
Начиная с C# 6 появилась возможность строить интерполированную строку, формат которой позволяет более просто, по сравнению с составным форматированием, рассмотренным нами выше, создавать строки. Интерполированная строка содержит специальные выражения интерполяции, они похожи на элементы форматирования. Выражения интерполяции имеют следующий вид:
{<interpolationExpression>[,<alignment>][:<formatString>]}
где interpolationExpression – элемент, значение, которого будет интегрироваться в строку;
alignment – выравнивание;
formatString – формат (см. форматирование строк).
Примеры работы с интерполированной строкой:
int n1 = 45678; double d1 = 123.34567; bool b1 = true; string sv = "test"; Console.WriteLine($"int val: {n1}, double val: {d1:#.###}"); Console.WriteLine($"bool val: {b1}, string val: {sv}");
Управляющие символы (литералы)
Управляющие символы позволяют вводить в текст команды управления кареткой и символы, которые имеют специальное назначение (одинарные и двойные кавычки). Ниже представлена таблица с управляющими символами.
Управляющий символ |
Описание |
\a |
Звуковой сигнал |
\b |
Возврат на одну позицию |
\f |
Перевод страницы |
\n |
Новая строка |
\r |
Возврат каретки |
\t |
Горизонтальная табуляция |
\v |
Вертикальная табуляция |
\0 |
Пустой символ |
\’ |
Одинарная кавычка |
\” |
Двойная кавычка |
\\ |
Обратная косая черта |
Пример использования управляющих символов:
Console.WriteLine("\aName:\t\"John\"\nAge:\t\"27\"");
@ – буквальный идентификатор
Еще один элемент, который можно использовать при создании срок – это буквальный идентификатор @. Если его поставить перед строкой, то она будет интерпретироваться буквально, в ней, escape-последовательности представляются без преобразования.
Пример работы с буквальным идентификатором:
Console.WriteLine(@"escape is not work: \a\t\n\x1234");
Класс StringBuilder
Класс StringBuilder следует использовать, если вам нужно собрать строку из большого набора элементов через конкатенацию, которая, например, может осуществляется в цикле. В этом случае использование String может оказаться не эффективным решением.
Если для построения итоговой строки использовать оператор +, как это сделано в примере ниже, то при выполнении операции += каждый раз будет создавать новый объект класса String в памяти. Если количество таких присваиваний будет достаточно большим, то программа может аварийно завершиться из-за нехватки памяти, либо занять ее в очень большом объеме. Это происходит из-за того, что сборщик мусора не будет успевать уничтожать неиспользуемые объекты, которые создаются с большой скоростью. Пример реализации с использованием оператора +:
string outString = ""; for(int i = 0; i < 10; i++) { outString += i.ToString() + " - "; } Console.WriteLine(outString);
Более эффективным решением будет использование StringBuilder:
StringBuilder sb = new StringBuilder(); for(int i = 0; i < 10; i++) { sb.Append(i.ToString()); sb.Append(" - "); } outString = sb.ToString(); Console.WriteLine(outString);
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.
спасибо великое! Вы меня спасли!