Строки и строковые литералы
Строка — это объект типа String значение которого — текст. Внутреннее хранение текста осуществляется в виде последовательной коллекции объектов Char, которые только для чтения. Свойство Length строки представляет количество объектов, содержащихся в Char
, а не число символов Юникода. Чтобы получить доступ к отдельным точкам кода Юникода в строке, используйте объект StringInfo.
string vs. System.String
В C#ключевое слово string
— это псевдоним для String; поэтому String
и string
эквивалентны. Используйте указанный псевдоним string
, так как он работает даже без using System;
. Класс String
предоставляет множество методов безопасного создания, управления и сравнения строк. Кроме того, язык C# перегружает некоторые операторы для упрощения общих строковых операций. Для получения дополнительной информации о ключевом слове см. строкув
Объявление и инициализация строк
Можно объявлять и инициализировать строки различными способами, как показано в следующем примере:
// Declare without initializing.
string message1;
// Initialize to null.
string? message2 = null;
// Initialize as an empty string.
// Use the Empty constant instead of the literal "".
string message3 = System.String.Empty;
// Initialize with a regular string literal.
string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0";
// Initialize with a verbatim string literal.
string newPath = @"c:\Program Files\Microsoft Visual Studio 9.0";
// Use System.String if you prefer.
System.String greeting = "Hello World!";
// In local variables (i.e. within a method body)
// you can use implicit typing.
var temp = "I'm still a strongly-typed System.String!";
// Use a const string to prevent 'message4' from
// being used to store another string value.
const string message4 = "You can't get rid of me!";
// Use the String constructor only when creating
// a string from a char*, char[], or sbyte*. See
// System.String documentation for details.
char[] letters = { 'A', 'B', 'C' };
string alphabet = new string(letters);
Вы не используете новый оператор для создания строкового объекта, за исключением при инициализации строки с массивом символов.
Инициализирует строку с константным значением Empty, чтобы создать новый объект String, строка которого равна нулевой длине. Строковое литеральное представление строки нулевой длины равно ""
. Инициализировав строки со значением Empty вместо null, можно уменьшить вероятность возникновения NullReferenceException. Используйте статический метод IsNullOrEmpty(String), чтобы проверить значение строки перед попыткой доступа к ней.
Неизменяемость строк
Строковые объекты неизменяемы: их нельзя изменить после их создания. Все методы String и операторы C#, которые, как представляется, изменяют строку, фактически возвращают результаты в новом строковом объекте. В следующем примере, когда содержимое s1
и s2
объединяются для формирования одной строки, две исходные строки не изменены. Оператор +=
создает новую строку, содержащую объединенное содержимое. Этот новый объект назначается переменной s1
, и исходный объект, назначенный s1
, освобождается для сборки мусора, так как другая переменная не содержит ссылку на нее.
string s1 = "A string is more ";
string s2 = "than the sum of its chars.";
// Concatenate s1 and s2. This actually creates a new
// string object and stores it in s1, releasing the
// reference to the original object.
s1 += s2;
System.Console.WriteLine(s1);
// Output: A string is more than the sum of its chars.
Поскольку "изменение строки" на самом деле означает создание новой строки, следует проявлять осторожность при создании ссылок на строки. Если вы создаете ссылку на строку, а затем изменяете исходную строку, ссылка продолжает указывать на исходный объект вместо нового объекта, созданного при изменении строки. Следующий код иллюстрирует это поведение:
string str1 = "Hello ";
string str2 = str1;
str1 += "World";
System.Console.WriteLine(str2);
//Output: Hello
Дополнительные сведения о создании новых строк, основанных на изменениях, таких как операции поиска и замены исходной строки, см. в разделе Изменение содержимого строки.
Строковые литералы в кавычках
строковые литералы начать и заканчивать одним двойным символом кавычки ("
) в одной строке. Кавычекные строковые литералы лучше всего подходят для строк, которые соответствуют одной строке и не включают в себя escape-последовательности. Строковый литерал в кавычках должен содержать escape-символы, как показано в следующем примере:
string columns = "Column 1\tColumn 2\tColumn 3";
//Output: Column 1 Column 2 Column 3
string rows = "Row 1\r\nRow 2\r\nRow 3";
/* Output:
Row 1
Row 2
Row 3
*/
string title = "\"The \u00C6olean Harp\", by Samuel Taylor Coleridge";
//Output: "The Æolean Harp", by Samuel Taylor Coleridge
Дословные строковые литералы
Дословные строковые литералы удобнее использовать для многостроковых строк, строк, содержащих символы обратной косой черты или встроенные двойные кавычки. Строки verbatim сохраняют символы новой строки в качестве части текста строки. Используйте двойные кавычки для внедрения внутренней кавычки в дословную строку. В следующем примере показаны некоторые распространенные способы использования дословных строк.
string title = "\"The \u00C6olean Harp\", by Samuel Taylor Coleridge";
//Output: "The Æolean Harp", by Samuel Taylor Coleridge
string filePath = @"C:\Users\scoleridge\Documents\";
//Output: C:\Users\scoleridge\Documents\
string text = @"My pensive SARA ! thy soft cheek reclined
Thus on mine arm, most soothing sweet it is
To sit beside our Cot,...";
/* Output:
My pensive SARA ! thy soft cheek reclined
Thus on mine arm, most soothing sweet it is
To sit beside our Cot,...
*/
string quote = @"Her name was ""Sara.""";
//Output: Her name was "Sara."
Необработанные строковые литералы
Начиная с C# 11, можно использовать необработанные строковые литералы для упрощения создания строк с несколькими строками или использования любых символов, требующих escape-последовательностей. Необработанные строковые литералы устраняют необходимость использования экранирующих последовательностей. Можно написать строку, включая форматирование пробелов, как она будет отображаться в выходных данных. необработанный строковый литерал:
- Начинается и заканчивается последовательностью по крайней мере трех двойных символов кавычки (
"""
). Вы можете использовать более трех последовательных символов, чтобы начинать и заканчивать последовательность, поддерживая строковые литералы, содержащие три или более повторяющихся символа кавычек. - Для однострочных необработанных строковых литералов символы открывающей и закрывающей кавычки должны находиться в одной строке.
- Многострочные сырой строковые литералы требуют как открывающие, так и закрывающие кавычки на отдельной строке.
- В многострочных необработанных строковых литералах все пробелы слева от закрывающих кавычек удаляются во всех строках.
- В многострочных необработанных строковых литералах пробелы после открывающей кавычки в той же строке игнорируются.
- В многострочных необработанных строковых литералах строки, состоящие только из пробелов и следующие за открывающей кавычкой, включаются в строковый литерал.
В следующих примерах демонстрируются следующие правила:
string singleLine = """Friends say "hello" as they pass by.""";
string multiLine = """
"Hello World!" is typically the first program someone writes.
""";
string embeddedXML = """
<element attr = "content">
<body style="normal">
Here is the main text
</body>
<footer>
Excerpts from "An amazing story"
</footer>
</element >
""";
// The line "<element attr = "content">" starts in the first column.
// All whitespace left of that column is removed from the string.
string rawStringLiteralDelimiter = """"
Raw string literals are delimited
by a string of at least three double quotes,
like this: """
"""";
В следующих примерах показаны ошибки компилятора, сообщаемые в соответствии с этими правилами:
// CS8997: Unterminated raw string literal.
var multiLineStart = """This
is the beginning of a string
""";
// CS9000: Raw string literal delimiter must be on its own line.
var multiLineEnd = """
This is the beginning of a string """;
// CS8999: Line does not start with the same whitespace as the closing line
// of the raw string literal
var noOutdenting = """
A line of text.
Trying to outdent the second line.
""";
Первые два примера недопустимы, так как многострочные необработанные строковые литералы требуют, чтобы открывающая и закрывающая последовательности кавычек были на собственной строке. Третий пример неправильный, так как текст выходит за пределы последовательности закрывающих кавычек.
Следует учитывать необработанные строковые литералы, если создавать текст, включающий символы, требующие использования escape-последовательностей , при работе с обычными или буквальными строковыми литералами. Необработанные строковые литералы проще для вас и других пользователей для чтения, так как они более похожи на выходной текст. Например, рассмотрим следующий код, содержащий строку форматированного JSON:
string jsonString = """
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00-07:00",
"2019-08-02T00:00:00-07:00"
],
"TemperatureRanges": {
"Cold": {
"High": 20,
"Low": -10
},
"Hot": {
"High": 60,
"Low": 20
}
},
"SummaryWords": [
"Cool",
"Windy",
"Humid"
]
}
""";
Escape-последовательности строк
Escape-последовательность | Имя персонажа | Кодировка Юникода |
---|---|---|
\' |
Одна кавычка | 0x0027 |
\" |
Двойная кавычка | 0x0022 |
\\ |
Обратная косая черта | 0x005C |
\0 |
Недействительный | 0x0000 |
\a |
Тревога | 0x0007 |
\b |
Backspace | 0x0008 |
\e |
Побег | 0x001B |
\f |
Подача формы | 0x000C |
\n |
Новая строка | 0x000A |
\r |
Возврат каретки | 0x000D |
\t |
Горизонтальная вкладка | 0x0009 |
\v |
Вертикальная вкладка | 0x000B |
\u |
Эскейп-последовательность Юникода (UTF-16) |
\uHHHH (диапазон: 0000 – FFFF; пример: \u00E7 = "ç") |
\U |
Эскейп-последовательность Юникода (UTF-32) |
\U00HHHHHH (диапазон: 000000 – 10FFFF; пример: \U0001F47D = "👽") |
\x |
Escape-последовательность Юникода похожа на "\u", за исключением переменной длины |
\xH[H][H][H] (диапазон: 0 – FFFF; пример: \x00E7 или \x0E7 или \xE7 = "ç") |
Предупреждение
При использовании escape-последовательности \x
и указании менее 4 шестнадцатеричных цифр, если символы, которые непосредственно следуют за escape-последовательностью, являются допустимыми шестнадцатеричными цифрами (т. е. 0-9, A-F и a-f), они будут интерпретированы как часть escape-последовательности. Например, \xA1
выводит "¡", что соответствует кодовой точке U+00A1. Однако, если следующий символ — это "A" или "a", то последовательность escape-последовательностей будет интерпретирована как \xA1A
и создастся "ਚ", что является кодовой точкой U+0A1A. В таких случаях указание всех 4 шестнадцатеричных цифр (например, \x00A1
) предотвращает любое возможное неправильное толкование.
Заметка
Во время компиляции буквальные и сырьевые строки преобразуются в обычные строки с теми же управляющими последовательностями. Таким образом, если вы просматриваете буквальную или необработанную строку в окне наблюдения отладчика, вы увидите символы экранирования, добавленные компилятором, а не буквальную или необработанную версию из вашего исходного кода. Например, строка @"C:\files.txt"
появится в окне просмотра как "C:\\files.txt"
.
Форматирование строк
Строка формата — это строка, содержимое которой определяется динамически во время выполнения. Строки форматирования создаются за счёт внедрения интерполированных выражений или заполнителей внутрь фигурных скобок, находящихся внутри строки. Все внутри фигурных скобок ({...}
) преобразуется в значение и отображается в формате строки во время выполнения. Существует два метода создания строк форматирования: интерполяция строк и составное форматирование.
Интерполяция строк
Вы объявляете интерполированные строки со специальным символом $
. Интерполированная строка включает интерполированные выражения в фигурных скобках. Если вы не знакомы с интерполяцией строк , ознакомьтесь с кратким обзором — интерактивным руководством по C#.
Используйте интерполяцию строк, чтобы улучшить удобочитаемость и удобство обслуживания кода. Интерполяция строк обеспечивает те же результаты, что и метод String.Format
, но повышает удобство использования и встроенную ясность.
var jh = (firstName: "Jupiter", lastName: "Hammon", born: 1711, published: 1761);
Console.WriteLine($"{jh.firstName} {jh.lastName} was an African American poet born in {jh.born}.");
Console.WriteLine($"He was first published in {jh.published} at the age of {jh.published - jh.born}.");
Console.WriteLine($"He'd be over {Math.Round((2018d - jh.born) / 100d) * 100d} years old today.");
// Output:
// Jupiter Hammon was an African American poet born in 1711.
// He was first published in 1761 at the age of 50.
// He'd be over 300 years old today.
Интерполяция строк позволяет инициализировать константную строку, если все выражения, используемые для заполнителей, также являются константными строками.
Начиная с C# 11, можно объединить необработанные строковые литералы с интерполяциями строк. Вы начинаете и заканчиваете строку формата тремя или более последовательными двойными кавычками. Если строка вывода должна содержать символ {
или }
, можно использовать дополнительные $
символы, чтобы указать, сколько {
и }
символов начинаются и заканчиваются интерполяцией. Любая последовательность меньшего числа {
или }
символов включается в выходные данные. В следующем примере показано, как использовать эту функцию для отображения расстояния точки от источника и размещения точки внутри фигурных скобок:
int X = 2;
int Y = 3;
var pointMessage = $$"""The point {{{X}}, {{Y}}} is {{Math.Sqrt(X * X + Y * Y)}} from the origin.""";
Console.WriteLine(pointMessage);
// Output:
// The point {2, 3} is 3.605551275463989 from the origin.
Интерполяция строк дословно
C# также позволяет дословную интерполяцию строк, например, на нескольких строках, с использованием синтаксиса $@
или @$
.
Чтобы буквально интерпретировать управляющие последовательности, используйте строковый литерал . Интерполированная дословная строка начинается с символа $
, за которым следует @
. Маркеры $
и @
можно использовать в любом порядке: $@"..."
и @$"..."
являются допустимыми интерполированными строками.
var jh = (firstName: "Jupiter", lastName: "Hammon", born: 1711, published: 1761);
Console.WriteLine($@"{jh.firstName} {jh.lastName}
was an African American poet born in {jh.born}.");
Console.WriteLine(@$"He was first published in {jh.published}
at the age of {jh.published - jh.born}.");
// Output:
// Jupiter Hammon
// was an African American poet born in 1711.
// He was first published in 1761
// at the age of 50.
Составное форматирование
String.Format использует плейсхолдеры в фигурных скобках для создания форматированной строки. Этот пример приводит к аналогичным выходным данным метода интерполяции строк, используемому в предыдущем примере.
var pw = (firstName: "Phillis", lastName: "Wheatley", born: 1753, published: 1773);
Console.WriteLine("{0} {1} was an African American poet born in {2}.", pw.firstName, pw.lastName, pw.born);
Console.WriteLine("She was first published in {0} at the age of {1}.", pw.published, pw.published - pw.born);
Console.WriteLine("She'd be over {0} years old today.", Math.Round((2018d - pw.born) / 100d) * 100d);
// Output:
// Phillis Wheatley was an African American poet born in 1753.
// She was first published in 1773 at the age of 20.
// She'd be over 300 years old today.
Дополнительные сведения о форматировании типов в .NET см. в Форматирование типов в .NET.
Подстроки
Подстрока — это любая последовательность символов, содержащихся в строке. Используйте метод Substring для создания новой строки из части исходной строки. Можно выполнить поиск одного или нескольких вхождений подстроки с помощью метода IndexOf. Используйте метод Replace, чтобы заменить все вхождения указанной подстроки новой строкой. Как и метод Substring, Replace фактически возвращает новую строку и не изменяет исходную строку. Дополнительные сведения см. в разделе Поиск строк и Изменение содержимого строки.
string s3 = "Visual C# Express";
System.Console.WriteLine(s3.Substring(7, 2));
// Output: "C#"
System.Console.WriteLine(s3.Replace("C#", "Basic"));
// Output: "Visual Basic Express"
// Index values are zero-based
int index = s3.IndexOf("C");
// index = 7
Доступ к отдельным символам
Вы можете использовать нотацию массива со значением индекса для получения доступа только для чтения к отдельным символам, как показано в следующем примере:
string s5 = "Printing backwards";
for (int i = 0; i < s5.Length; i++)
{
System.Console.Write(s5[s5.Length - i - 1]);
}
// Output: "sdrawkcab gnitnirP"
Если методы String не предоставляют необходимых функций для изменения отдельных символов в строке, можно использовать объект StringBuilder для модификации символов "на месте", а затем создать новую строку для хранения результатов, используя методы StringBuilder. В следующем примере предположим, что необходимо изменить исходную строку определенным образом, а затем сохранить результаты для дальнейшего использования:
string question = "hOW DOES mICROSOFT wORD DEAL WITH THE cAPS lOCK KEY?";
System.Text.StringBuilder sb = new System.Text.StringBuilder(question);
for (int j = 0; j < sb.Length; j++)
{
if (System.Char.IsLower(sb[j]) == true)
sb[j] = System.Char.ToUpper(sb[j]);
else if (System.Char.IsUpper(sb[j]) == true)
sb[j] = System.Char.ToLower(sb[j]);
}
// Store the new string.
string corrected = sb.ToString();
System.Console.WriteLine(corrected);
// Output: How does Microsoft Word deal with the Caps Lock key?
Строки NULL и пустые строки
Пустая строка — это экземпляр объекта System.String, содержащего нулевые символы. Пустые строки часто используются в различных сценариях программирования для представления пустого текстового поля. На пустых строках можно вызывать методы, так как они являются допустимыми объектами типа System.String. Пустые строки инициализированы следующим образом:
string s = String.Empty;
В отличие от этого, строка NULL не ссылается на экземпляр объекта System.String и любая попытка вызвать метод в строке NULL вызывает NullReferenceException. Однако можно использовать null-строки в сцеплении и операциях сравнения с другими строками. В следующих примерах показаны некоторые случаи, в которых ссылка на строку NULL не вызывает исключение:
string str = "hello";
string? nullStr = null;
string emptyStr = String.Empty;
string tempStr = str + nullStr;
// Output of the following line: hello
Console.WriteLine(tempStr);
bool b = (emptyStr == nullStr);
// Output of the following line: False
Console.WriteLine(b);
// The following line creates a new empty string.
string newStr = emptyStr + nullStr;
// Null strings and empty strings behave differently. The following
// two lines display 0.
Console.WriteLine(emptyStr.Length);
Console.WriteLine(newStr.Length);
// The following line raises a NullReferenceException.
//Console.WriteLine(nullStr.Length);
// The null character can be displayed and counted, like other chars.
string s1 = "\x0" + "abc";
string s2 = "abc" + "\x0";
// Output of the following line: * abc*
Console.WriteLine("*" + s1 + "*");
// Output of the following line: *abc *
Console.WriteLine("*" + s2 + "*");
// Output of the following line: 4
Console.WriteLine(s2.Length);
Использование StringBuilder для быстрого создания строк
Строковые операции в .NET высоко оптимизированы и в большинстве случаев не оказывают значительного влияния на производительность. Однако в некоторых сценариях, таких как жесткие циклы, выполняющие много сотен или тысяч раз, строковые операции могут повлиять на производительность. Класс StringBuilder создает строковый буфер, который обеспечивает более высокую производительность, если программа выполняет множество строковых манипуляций. Строка StringBuilder также позволяет переназначать отдельные символы, чего встроенный тип данных строки не поддерживает. Например, этот код изменяет содержимое строки без создания новой строки:
System.Text.StringBuilder sb = new System.Text.StringBuilder("Rat: the ideal pet");
sb[0] = 'C';
System.Console.WriteLine(sb.ToString());
//Outputs Cat: the ideal pet
В этом примере объект StringBuilder используется для создания строки из набора числовых типов:
var sb = new StringBuilder();
// Create a string composed of numbers 0 - 9
for (int i = 0; i < 10; i++)
{
sb.Append(i.ToString());
}
Console.WriteLine(sb); // displays 0123456789
// Copy one character of the string (not possible with a System.String)
sb[0] = sb[9];
Console.WriteLine(sb); // displays 9123456789
Строки, методы расширения и LINQ
Поскольку тип String реализует IEnumerable<T>, можно использовать методы расширения, определенные в классе Enumerable для строк. Чтобы избежать визуального загромождений, эти методы исключаются из IntelliSense для типа String, но они доступны тем не менее. Выражения запросов LINQ также можно использовать в строках. Дополнительные сведения см. в разделе LINQ иStrings.
Связанные статьи
- Как изменить содержимое строки: иллюстрирует методы преобразования строк и изменения содержимого строк.
- Сравнение строк. Демонстрирует, как выполнять порядковые и культурно специфичные сравнения строк.
- Как объединить несколько строк: демонстрирует различные способы объединения нескольких строк в одну.
- Как анализировать строки с помощью String.Split: содержит примеры кода, иллюстрирующие использование метода String.Split для анализа строк.
- Как искать строки: объясняется, как использовать поиск определенного текста или шаблонов в строках.
- Как определить, представляет ли строка числовое значение: показывает, как безопасно проанализировать строку, чтобы узнать, имеет ли он допустимое числовое значение.
- Интерполяция строк: Описывает функцию интерполяции строк, которая предоставляет удобный синтаксис для форматирования строк.
- Базовые Строковые Операции: содержит ссылки на статьи, использующие методы System.String и System.Text.StringBuilder для выполнения базовых строковых операций.
- синтаксический анализ строк. Описывает преобразование строковых представлений базовых типов .NET в экземпляры соответствующих типов.
- синтаксический анализ строк даты и времени в.NET: показывает, как преобразовать строку, например "01/24/2008" в объект System.DateTime.
- сравнение строк: содержит сведения о том, как сравнивать строки и приведены примеры в C# и Visual Basic.
- Использование класса StringBuilder: описывает создание и изменение динамических строковых объектов с помощью класса StringBuilder.
- LINQ и Strings: содержит сведения о выполнении различных строковых операций с помощью запросов LINQ.