
- •7. Лекция: Символы и строки
- •Общий взгляд
- •Класс char
- •Класс char[] - массив символов
- •Существует ли в c# строки типа char*
- •Класс String
- •Объявление строк. Конструкторы класса string
- •Операции над строками
- •Строковые константы
- •Неизменяемый класс string
- •Статические свойства и методы класса string
- •Метод Format
- •Методы Join и Split
- •Динамические методы класса string
- •Класс StringBuilder - построитель строк
- •Объявление строк. Конструкторы класса StringBuilder
- •Операции над строками
- •Основные методы
- •Емкость буфера
- •Архитектура Решения
- •Алгоритмы и задачи
- •Проекты
- •Поиск и Сортировка
- •Линейный поиск
- •Поиск с барьером
- •Бинарный поиск
- •Сортировка
- •Методы сортировки за время порядка o(n2)
- •Сортировка SortMin (SortMax)
- •Сортировка SortMinMax
- •Сортировка SortBubble (SortBall)
- •Сортировка SortShaker
- •Сортировка SortInsert - сортировка вставками
- •Сортировка SortShell - улучшенный вариант сортировки вставками
- •Проекты
- •Рекурсивные методы сортировки за время порядка o(n*log2(n))
- •Сортировка за линейное время
- •Задача "Красные и белые"
- •Задача Дейкстры "о голландском национальном флаге"
- •Задача Гарри Поттера "Сортировочная шляпа"
- •Сортировка массивов с элементами m типов
- •Сортировка черпаками
- •Проекты
-
Строковые константы
Без констант не обойтись. В C# существуют два вида строковых констант:
-
обычные константы, которые представляют строку символов, заключенную в кавычки;
-
@-константы, заданные обычной константой c предшествующим знаком @.
В обычных константах некоторые символы интерпретируются особым образом. Связано это, прежде всего, с тем, что необходимо уметь задавать в строке непечатаемые символы, такие как, например, символ табуляции. Возникает необходимость задавать символы в виде escape-последовательностей. Для всех этих целей используется комбинация символов, начинающаяся символом "\" - обратная косая черта. Так, пары символов: "\n", "\t", "\\", "\"" задают соответственно символ перехода на новую строку, символ табуляции, сам символ обратной косой черты, символ кавычки, вставляемый в строку, но не сигнализирующий о ее окончании. Комбинация "\xNNNN" задает символ, определяемый шестнадцатеричным кодом NNNN. Хотя такое решение возникающих проблем совершенно естественно, иногда возникают неудобства: например, при задании констант, определяющих путь к файлу, приходится каждый раз удваивать символ обратной косой черты. Это одна из причин, по которой появились @-константы.
В @-константах все символы трактуются в полном соответствии с их изображением. Поэтому путь к файлу лучше задавать @-константой. Единственная проблема в таких случаях: как задать символ кавычки, чтобы он не воспринимался как конец самой константы. Решением является удвоение символа. Вот соответствующие примеры:
/// <summary>
/// Два вида констант
/// </summary>
public void TestConstants()
{
string s1 = "\x50";
string s2 = @"\x50""";
bool b1 = (s1 == s2);
Console.WriteLine("s1={0}, s2={1}, b1={2}",
s1, s2, b1);
s1 = "c:\\c#book\\ch5\\chapter5.doc";
s2 = @"c:\c#book\ch5\chapter5.doc";
b1 = (s1 == s2);
Console.WriteLine("s1={0}, s2={1}, b1={2}",
s1, s2, b1);
s1 = "\"A\"";
s2 = @"""A""";
b1 = (s1 == s2);
Console.WriteLine("s1={0}, s2={1}, b1={2}",
s1, s2, b1);
}
Первая проверка эквивалентности строк в этом примере даст значение False, остальные - True.
-
Неизменяемый класс string
В языке C# существует понятие неизменяемый (immutable) класс. Для такого класса невозможно изменить значение объекта. Методы могут создавать новый объект на основе существующего, но не могут изменить значение существующего объекта.
К таким неизменяемым классам относится и класс string. Ни один из методов этого класса не меняет значения существующих объектов. Когда метод изменяет строку, результатом является новая строка - новый объект в куче. Невозможность изменять значения строк касается не только методов. Аналогично при работе со строкой как с массивом разрешено только чтение отдельных символов, но не их замена. Оператор присваивания, в котором делается попытка изменить первый символ строки, не допустим, а потому закомментирован:
//Неизменяемые значения
s1= "Zenon"; ch1 = s1[0];
//s1[0]='L';
По какой причине на класс string наложены такие строгие ограничения? Цель благая. Хотя класс string по целому ряду причин целесообразно отнести к ссылочным типам, но для переменных этого типа хотелось бы иметь ту же семантику, что и для переменных арифметического типа, полагая, что каждая переменная имеет собственную память. Неизменяемость типа обеспечивает эту семантику. Поясним ситуацию на примере.
/// <summary>
/// String - неизменяемый тип данных!
/// </summary>
public void TestUnchanged()
{
string s1 = "Zenon";
string s2 = s1;
Console.WriteLine( "s1 = " + s1 + "\t s2 = " + s2);
Обе переменные указывают на один объект, у них общая память, одно и то же значение. Представим себе, что s1 хочет изменить свое значение, вызвав метод Insert для вставки нового текста. Но метод Insert класса string реализован как функция, возвращающая строку в качестве результата. Поэтому возможно лишь такое присваивание
s1 = s1.Insert(s1.Length, " - это философ!");
Console.WriteLine( "s1 = " + s1 + "\t s2 = " + s2);
Теперь в куче два объекта, s1 стала ссылкой на вновь созданный объект, изменение ее значения никак не отразилось на переменной s2. Переменная s2 также может изменить свое значение, например, так:
s2 = s2.Replace(s2[0], 'L') + " - это музыкант!";
Console.WriteLine( "s1 = " + s1 + "\t s2 = " + s2);
}
Строка "Zenon" осталась в куче висячей, без ссылок на нее и является объектом для сборщика мусора. Как видите, невозможность изменять значение строки непосредственно в памяти, где хранится ее значение, гарантирует, что изменение значения строковой переменной никак не отражается на других строковых переменных - это соответствует семантике поведения развернутых типов.
На рис. 7.3 показаны результаты работы метода TestUnchanged.
Рис. 7.3. Тип string - это неизменяемый тип