Содержание
Большое количество задач (если не большинство) при разработке программного обеспечения так или иначе связано с обработкой строк будь то простой вывод в консоль определенных значений, сравнение строк или парсинг текста web-страниц. Даже при первом знакомстве с языком программирования, первое, что мы делаем — это используем строки («Hello world» и т.д.). Именно поэтому умение работы со строками в C#, как и в любом другом языке программирования, является одним из необходимых и важных навыков программиста. В этой и нескольких последующих статьях мы рассмотрим основные возможности работы со строками в C#.
Строка в C#
Строки в C# относятся к неизменяемым типам данных и представляют собой объекты класса System.String
. Объекты этого класса представляют текст в виде последовательности символов Unicode. При необходимости, никто не мешает нам изменять кодировку символов в строке C# и об этом мы тоже поговорим.
Для тех, кто уже имел дело с другими языками программирования, не лишним будет знать, что в конце строки C# нет нуль-символов. Поэтому в C# мы можем создавать строки, которые содержат любое количество внедренных нуль-символов (\0
). При этом, максимальный размер объекта String
в памяти составляет 2 Гб.
Создание строк в C#
Объявление и создание строк в C# можно осуществить несколькими способами. Рассмотрим основные из них.
string str1; //объявили переменную типа string str1 = "Привет";//присвоили строке значение //объявили и создали строку из двух символов 'a' string str2 = new String('a', 2); //объявили и создали строку из массива символов char[] letters = { 'H', 'e', 'l', 'l', 'o' }; string helloString = new string(letters); //объявили и создали пустую строку string emptyStr = string.Empty;
В любом из представленных выше примеров мы создаем строку, при этом, в последнем случае, мы создаем пустую строку без символов. Так как строки относятся к ссылочным типам данных, то никто нам не запрещает присвоить строке значение null
string nullStr = null;
хотя, разработчики C# и предупреждают нас о том, что использование string.Empty
вместо null
предпочтительнее и снижает вероятность получения исключения типа NullReferenceException
.
Строки с регулярными и буквальными литералами
Отдельное внимание при создании строк также стоит уделить такому моменту, как создание строк, содержащих какие-либо служебные символы. Например, если вам необходимо присвоить строке значение, указывающее на путь к файлу: c:\Program Files\dotnet\dotnet.exe
. Если вы попробуете присвоить строке это значение как есть, то ваша программа даже не будет скомпилирована, так как Visual Studio укажет вам на ошибку:
Все дело в том, что символ обратной косой черты \
используется в строках для указания так называемых escape-последовательностей и для того, чтобы создать строку, содержащую символ \
нам необходимо либо регулярный строковый литерал, либо буквальный литерал, как показано ниже:
//использование регулярного литерала string path = "c:\\Program Files\\dotnet\\dotnet.exe"; //использование буквального литерала string path2 = @"c:\Program Files\dotnet\dotnet.exe";
Использование регулярного литерала позволяет нам использовать различные escape-последовательности в строках. В таблице ниже представлены основные escape-последовательности в C#:
Escape-последовательность | Имя символа | Кодировка Юникод |
\’ | Одинарная кавычка | 0x0027 |
\» | Двойная кавычка | 0x0022 |
\\ | Обратная косая черта | 0x005C |
\0 | Null | 0x0000 |
\a | Предупреждение | 0x0007 |
\b | Backspace | 0x0008 |
\f | Перевод страницы | 0x000C |
\n | Новая строка | 0x000A |
\r | Возврат каретки | 0x000D |
\t | Горизонтальная табуляция | 0x0009 |
\v | Вертикальная табуляция | 0x000B |
\u | Escape-последовательность Юникода (UTF-16) | \uHHHH (диапазон: 0000–FFFF; пример: \u00E7 = «ç») |
\U | Escape-последовательность Юникода (UTF-32) | \U00HHHHHH (диапазон: 000000–10FFFF; пример: \U0001F47D = «👽») |
\x | Escape-последовательность Юникода аналогична «\u», она отличается только длиной переменной | \xH[H][H][H] (диапазон: 0–FFFF; пример: \x00E7 или \x0E7 или \xE7 = «ç») |
Например, используя escape-последовательности, мы можем вывести в консоль таблицу:
//выводим в консоль таблицу 3х3 Console.WriteLine("Номер\tЗначение\tОписание"); Console.WriteLine("1\t0,1\t\tописание 1"); Console.WriteLine("2\t0,2\t\tописание 2"); Console.WriteLine("3\t0,3\t\tописание 3");
В итоге, в консоли мы увидим вот такую красивую табличку:
Что касается использования буквального литерала в строках, то его удобно использовать для того, чтобы сделать строки, содержащие какие-либо служебные символы, более читабельными. Согласитесь, что такая строка:
string path2 = @"c:\Program Files\dotnet\dotnet.exe";
выглядит более читабельной, чем вот такая:
string path = "c:\\Program Files\\dotnet\\dotnet.exe";
Более того, так как буквальный литерал позволяет сохранять все символы в строке как есть, то, используя его, мы можем использовать в наших строках переносы, кавычки и прочие символы как есть, например:
//использование буквального литерала string str = @"Эта строка содержит символ \ , а также одинарные кавычки 'текст в кавычках' и переносы строки ";
В результате, в консоли мы увидим следующий текст:
Неизменяемость строк в C#
Как уже упоминалось выше, строки в C# относятся к неизменяемым типам данных. Что это значит для нас? А это значит, что при каждом присвоении значения переменной типа string
система вначале освобождает память, занятую строкой, а затем выделяет по новой и только потом записывает новое значение. С одной стороны, подобный подход выглядит нерациональным — лишние освобождения и выделения памяти, но, с другой стороны, таким образом разработчики C# обеспечили максимальную безопасность работы со строками и, надо сказать, сделали это достаточно элегантно и понятно. Например,
string str4; //объявили переменную str4 = "hello"; //выделили память под 5 символов и присвоили значение переменной str4 = "hello world";//освободили память, по новой выделили память уже под 11 символов и присвоили новое значение
Также стоит отметить, что когда содержимое двух строк, например, s1
и s2
объединяется для формирования строки, то две исходные строки не изменяются. Например:
string s1 = "Hello "; string s2 = "world"; s1 += s2; Console.WriteLine(s1);
В примере выше оператор +=
создает новую строку, которая содержит объединенное содержимое двух строк. Этот новый объект присваивается переменной s1
, а исходный объект, который был присвоен s1
, освобождается для сборки мусора, так как ни одна переменная не ссылается на него.
Если вы создадите ссылку на строку, а затем «измените» исходную строку, ссылка будет по-прежнему указывать на исходный объект, а не на новый, который был создан при изменении строки. Пример:
string s1 = "Hello "; string s2 = s1; s1 += "World"; Console.WriteLine(s2);
В представленном примере может показаться, что в итоге, в консоли будет строка "Hello world"
, однако, на самом деле в консоли мы увидим только "Hello "
так как строка s2
остается неизменной.
Итого
Сегодня мы узнали как создавать строки в C#, как использовать различные escape-последовательности в строках, а также использовать буквальный литерал для повышения читабельности строк в C#. Также рассмотрели некоторые моменты, касающиеся неизменности строк в C# и как эта неизменность проявляется.