Класс String
Автор: admin | 20 Июнь 2008 – 21:23 -Класс String
В предыдущей лекции мы говорили о символьном типе char и строках постоянной длины, задаваемых массивом символов. Основным типом при работе со строками является тип string, задающий строки переменной длины. Класс String в языке C# относится к ссылочным типам. Над строками – объектами этого класса – определен широкий набор операций, соответствующий современному представлению о том, как должен быть устроен строковый тип.
Объявление строк. Конструкторы класса string
Объекты класса String объявляются как все прочие объекты простых типов – с явной или отложенной инициализацией, с явным или неявным вызовом конструктора класса. Чаще всего, при объявлении строковой переменной конструктор явно не вызывается, а инициализация задается строковой константой. Но у класса Sring достаточно много конструкторов. Они позволяют сконструировать строку из:
- символа, повторенного заданное число раз;
- массива символов char[];
- части массива символов.
Некоторым конструкторам в качестве параметра инициализации можно передать строку, заданную типом char*. Но все это небезопасно, и подобные примеры приводиться и обсуждаться не будут. Приведу примеры объявления строк с вызовом разных конструкторов:
public void TestDeclStrings()
{
//конструкторы
string world = “Мир”;
//string s1 = new string(“s1″);
//string s2 = new string();
string sssss = new string(’s’,5);
char[] yes = “Yes”.ToCharArray();
string stryes = new string(yes);
string strye = new string(yes,0,2);
Console.WriteLine(“world = {0}; sssss={1}; stryes={2};”+
” strye= {3}”, world, sssss, stryes, strye);
}
Объект world создан без явного вызова конструктора, а объекты sssss, stryes, strye созданы разными конструкторами класса String.
Заметьте, не допускается явный вызов конструктора по умолчанию – конструктора без параметров. Нет также конструктора, которому в качестве аргумента можно передать обычную строковую константу. Соответствующие операторы в тексте закомментированы.
Операции над строками
Над строками определены следующие операции:
- присваивание (=);
- две операции проверки эквивалентности (= =) и (!=);
- конкатенация или сцепление строк (+);
- взятие индекса ([]).
Начну с присваивания, имеющего важную особенность. Поскольку string – это ссылочный тип, то в результате присваивания создается ссылка на константную строку, хранимую в “куче”. С одной и той же строковой константой в “куче” может быть связано несколько переменных строкового типа. Но эти переменные не являются псевдонимами – разными именами одного и того же объекта. Дело в том, что строковые константы в “куче” не изменяются (о неизменяемости строкового типа будем далее говорить подробно), поэтому когда одна из переменных получает новое значение, она связывается с новым константным объектом в “куче”. Остальные переменные сохраняют свои связи. Для программиста это означает, что семантика присваивания строк аналогична семантике значимого присваивания.
В отличие от других ссылочных типов операции, проверяющие эквивалентность, сравнивают значения строк, а не ссылки. Эти операции выполняются как над значимыми типами.
Бинарная операция “+” сцепляет две строки, приписывая вторую строку к хвосту первой.
Возможность взятия индекса при работе со строками отражает тот приятный факт, что строку можно рассматривать как массив и получать без труда каждый ее символ. Каждый символ строки имеет тип char, доступный только для чтения, но не для записи.
Вот пример, в котором над строками выполняются данные операции:
public void TestOpers()
{
//операции над строками
string s1 =”ABC”, s2 =”CDE”;
string s3 = s1+s2;
bool b1 = (s1==s2);
char ch1 = s1[0], ch2=s2[0];
Console.WriteLine(“s1={0}, s2={1}, b1={2},” +
“ch1={3}, ch2={4}”, s1,s2,b1,ch1,ch2);
s2 = s1;
b1 = (s1!=s2);
ch2 = s2[0];
Console.WriteLine(“s1={0}, s2={1}, b1={2},” +
“ch1={3}, ch2={4}”, s1,s2,b1,ch1,ch2);
//Неизменяемые значения
s1= “Zenon”;
//s1[0]=’L';
}
Строковые константы
Без констант не обойтись. В C# существуют два вида строковых констант:
- обычные константы, которые представляют строку символов, заключенную в кавычки;
- @-константы, заданные обычной константой c предшествующим знаком @.
В обычных константах некоторые символы интерпретируются особым образом. Связано это прежде всего с тем, что необходимо уметь задавать в строке непечатаемые символы, такие, как, например, символ табуляции. Возникает необходимость задавать символы их кодом – в виде escape-последовательностей. Для всех этих целей используется комбинация символов, начинающаяся символом “\” – обратная косая черта. Так, пары символов: “\n“, “\t“, “\\“, “\“” задают соответственно символ перехода на новую строку, символ табуляции, сам символ обратной косой черты, символ кавычки, вставляемый в строку, но не сигнализирующий о ее окончании. Комбинация “\xNNNN” задает символ, определяемый шестнадцатеричным кодом NNNN. Хотя такое решение возникающих проблем совершенно естественно, иногда возникают неудобства: например, при задании констант, определяющих путь к файлу, приходится каждый раз удваивать символ обратной косой черты. Это одна из причин, по которой появились @-константы.
В @-константах все символы трактуются в полном соответствии с их изображением. Поэтому путь к файлу лучше задавать @-константой. Единственная проблема в таких случаях: как задать символ кавычки, чтобы он не воспринимался как конец самой константы. Решением является удвоение символа. Вот соответствующие примеры:
//Два вида констант
s1= “\x50″;
s2=@”\x50″”";
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);
Взгляните на результаты работы приведенных фрагментов кода, полученные при вызове процедур TestDeclStrings и TestOpers.

Рис. 14.1. Объявления, константы и операции над объектами string
Неизменяемый класс string
В языке C# существует понятие неизменяемый (immutable) класс. Для такого класса невозможно изменить значение объекта при вызове его методов. Динамические методы могут создавать новый объект, но не могут изменить значение существующего объекта.
К таким неизменяемым классам относится и класс String. Ни один из методов этого класса не меняет значения существующих объектов. Конечно, некоторые из методов создают новые значения и возвращают в качестве результата новые строки. Невозможность изменять значения строк касается не только методов. Аналогично, при работе со строкой как с массивом разрешено только чтение отдельных символов, но не их замена. Оператор присваивания из нашего последнего примера, в котором делается попытка изменить первый символ строки, недопустим, а потому закомментирован.
//Неизменяемые значения
s1= “Zenon”; ch1 = s1[0];
//s1[0]=’L';
Статические свойства и методы класса String
|
Таблица 14.1. Статические методы и свойства класса String |
|
|
Метод |
Описание |
| Empty | Возвращается пустая строка. Свойство со статусом read only |
| Compare | Сравнение двух строк. Метод перегружен. Реализации метода позволяют сравнивать как строки, так и подстроки. При этом можно учитывать или не учитывать регистр, особенности национального форматирования дат, чисел и т.д. |
| CompareOrdinal | Сравнение двух строк. Метод перегружен. Реализации метода позволяют сравнивать как строки, так и подстроки. Сравниваются коды символов |
| Concat | Конкатенация строк. Метод перегружен, допускает сцепление произвольного числа строк |
| Copy | Создается копия строки |
| Format | Выполняет форматирование в соответствии с заданными спецификациями формата. Ниже приведено более полное описание метода |
| Intern, IsIntern | Отыскивается и возвращается ссылка на строку, если таковая уже хранится во внутреннем пуле данных. Если же строки нет, то первый из методов добавляет строку во внутренний пул, второй – возвращает null. Методы применяются обычно тогда, когда строка создается с использованием построителя строк – класса StringBuilder |
| Join | Конкатенация массива строк в единую строку. При конкатенации между элементами массива вставляются разделители. Операция, заданная методом Join, является обратной к операции, заданной методом Split. Последний является динамическим методом и, используя разделители, осуществляет разделение строки на элементы |
Метод Format
Метод Format в наших примерах встречался многократно. Всякий раз, когда выполнялся вывод результатов на консоль, неявно вызывался и метод Format. Рассмотрим оператор печати:
Console.WriteLine(“s1={0}, s2={1}”, s1,s2);
Здесь строка, задающая первый аргумент метода, помимо обычных символов, содержит форматы, заключенные в фигурные скобки. В данном примере используется простейший вид формата – он определяет объект, который должен быть подставлен в участок строки, занятый данным форматом. Помимо неявных вызовов, нередко возникает необходимость явного форматирования строки.
Давайте рассмотрим общий синтаксис как самого метода Format, так и используемых в нем форматов. Метод Format, как и большинство методов, является перегруженным и может вызываться с разным числом параметров. Первый необязательный параметр метода задает провайдера, определяющего национальные особенности, которые используются в процессе форматирования. В качестве такого параметра должен быть задан объект, реализующий интерфейс System.IFormatProvider. Если этот параметр не задан, то используется культура, заданная по умолчанию. Вот примеры двух реализаций этого метода:
public static string Format(string, object);
public static string Format(IFormatProvider, string, params object[]);
Параметр типа string задает форматируемую строку. Заданная строка содержит один или несколько форматов, они распознаются за счет окружающих формат фигурных скобок. Число форматов, вставленных в строку, определяет и число объектов, передаваемых при вызове метода Format. Каждый формат определяет форматирование объекта, на который он ссылается и который, после преобразования его в строку, будет подставлен в результирующую строку вместо формата. Метод Format в качестве результата возвращает переданную ему строку, где все спецификации формата заменены строками, полученными в результате форматирования объектов.
Общий синтаксис, специфицирующий формат, таков:
{N [,M [:<коды_форматирования>]]}
Обязательный параметр N задает индекс объекта, заменяющего формат. Можно считать, что методу всегда передается массив объектов, даже если фактически передан один объект. Индексация объектов начинается с нуля, как это принято в массивах. Второй параметр M, если он задан, определяет минимальную ширину поля, которое отводится строке, вставляемой вместо формата. Третий необязательный параметр задает коды форматирования, указывающие, как следует форматировать объект. Например, код C (Currency) говорит о том, что параметр должен форматироваться как валюта с учетом национальных особенностей представления. Код P (Percent) задает форматирование в виде процентов с точностью до сотой доли.
Все становится ясным, когда появляются соответствующие примеры. Вот они:
public void TestFormat()
{
//метод Format
int x=77;
string s= string.Format(“x={0}”,x);
Console.WriteLine(s + “\tx={0}”,x);
s= string.Format(“Итого:{0,10} рублей”,x);
Console.WriteLine(s);
s= string.Format(“Итого:{0,6:######} рублей”,x);
Console.WriteLine(s);
s= string.Format(“Итого:{0:P} “,0.77);
Console.WriteLine(s);
s= string.Format(“Итого:{0,4:C} “,77.77);
Console.WriteLine(s);
//Национальные особенности
System.Globalization.CultureInfo ci =
new System.Globalization.CultureInfo(“en-US”);
s= string.Format(ci,”Итого:{0,4:C} “,77.77);
Console.WriteLine(s);
}//TestFormat
Приведу некоторые комментарии к этой процедуре. Вначале демонстрируется, что и явный, и неявный вызовы метода Format дают один и тот же результат. В дальнейших примерах показано использование различных спецификаций формата с разным числом параметров и разными кодами форматирования. В частности, показан вывод процентов и валют. В последнем примере с валютами демонстрируется задание провайдером национальных особенностей. С этой целью создается объект класса CultureInfo, инициализированный так, чтобы он задавал особенности форматирования, принятые в США. Заметьте, класс CultureInfo наследует интерфейс IFormatProvider. Российские национальные особенности форматирования установлены по умолчанию. При необходимости их можно установить таким же образом, как это сделано для США, задав соответственно константу “ru-RU“. Результаты работы метода показаны на рис. 14.2.

Рис. 14.2. Результаты работы метода Format
Методы Join и Split
Методы Join и Split выполняют над строкой текста взаимно обратные преобразования. Динамический метод Split позволяет осуществить разбор текста на элементы. Статический метод Join выполняет обратную операцию, собирая строку из элементов.
Заданный строкой текст зачастую представляет собой совокупность структурированных элементов – абзацев, предложений, слов, скобочных выражений и т.д. При работе с таким текстом необходимо разделить его на элементы, пользуясь специальными разделителями элементов, – это могут быть пробелы, скобки, знаки препинания. Практически подобные задачи возникают постоянно при работе со структурированными текстами. Методы Split и Join облегчают решение этих задач.
Динамический метод Split, как обычно, перегружен. Наиболее часто используемая реализация имеет следующий синтаксис:
public string[] Split(params char[])
На вход методу Split передается один или несколько символов, интерпретируемых как разделители. Объект string, вызвавший метод, разделяется на подстроки, ограниченные этими разделителями. Из этих подстрок создается массив, возвращаемый в качестве результата метода. Другая реализация позволяет ограничить число элементов возвращаемого массива.
Синтаксис статического метода Join таков:
public static string Join(string delimiters, string[] items )
В качестве результата метод возвращает строку, полученную конкатенацией элементов массива items, между которыми вставляется строка разделителей delimiters. Как правило, строка delimiters состоит из одного символа, который и разделяет в результирующей строке элементы массива items; но в отдельных случаях ограничителем может быть строка из нескольких символов.
Рассмотрим примеры применения этих методов. В первом из них строка представляет сложноподчиненное предложение, которое разбивается на простые предложения. Во втором предложение разделяется на слова. Затем производится обратная сборка разобранного текста. Вот код соответствующей процедуры:
public void TestSplitAndJoin()
{
string txt = “А это пшеница, которая в темном чулане
хранится,” +” в доме, который построил Джек!”;
Console.WriteLine(“txt={0}”, txt);
Console.WriteLine(“Разделение текста на простые предложения:”);
string[] SimpleSentences, Words;
//размерность массивов SimpleSentences и Words
//устанавливается автоматически в соответствии с
//размерностью массива, возвращаемого методом Split
SimpleSentences = txt.Split(‘,’);
for(int i=0;i< SimpleSentences.Length; i++)
Console.WriteLine(“SimpleSentences[{0}]= {1}”,
i, SimpleSentences[i]);
string txtjoin = string.Join(“,”,SimpleSentences);
Console.WriteLine(“txtjoin={0}”, txtjoin);
Words = txt.Split(‘,’, ‘ ‘);
for(int i=0;i< Words.Length; i++)
Console.WriteLine(“Words[{0}]= {1}”,i, Words[i]);
txtjoin = string.Join(” “,Words);
Console.WriteLine(“txtjoin={0}”, txtjoin);
}//TestSplitAndJoin
Результаты выполнения этой процедуры показаны на рис. 14.3.

Рис. 14.3. Разбор и сборка строки текста
Обратите внимание, что методы Split и Join хорошо работают, когда при разборе используется только один разделитель. В этом случае сборка действительно является обратной операцией и позволяет восстановить исходную строку. Если же при разборе задается некоторое множество разделителей, то возникают две проблемы:
- невозможно при сборке восстановить строку в прежнем виде, поскольку не сохраняется информация о том, какой из разделителей был использован при разборе строки. Поэтому при сборке между элементами вставляется один разделитель, возможно, состоящий из нескольких символов;
- при разборе двух подряд идущих разделителей предполагается, что между ними находится пустое слово. Обратите внимание в тексте нашего примера, как и положено, после запятой следует пробел. При разборе текста на слова в качестве разделителей указаны символы пробела и запятой. По этой причине в массиве слов, полученном в результате разбора, имеются пустые слова.
Если при разборе предложения на слова использовать в качестве разделителя только пробел, то пустые слова не появятся, но запятая будет являться частью некоторых слов.
Как всегда, есть несколько способов справиться с проблемой. Один из них состоит в том, чтобы написать собственную реализацию этих функций, другой – в корректировке полученных результатов, третий – в использовании более мощного аппарата регулярных выражений, и о нем мы поговорим чуть позже.
Динамические методы класса String
Операции, разрешенные над строками в C#, разнообразны. Методы этого класса позволяют выполнять вставку, удаление, замену, поиск вхождения подстроки в строку. Класс String наследует методы класса Object, частично их переопределяя. Класс String наследует и, следовательно, реализует методы четырех интерфейсов: IComparable, ICloneable, IConvertible, IEnumerable. Три из них уже рассматривались при описании классов-массивов.
Рассмотрим наиболее характерные методы при работе со строками.
Сводка методов, приведенная в таблице 14.2, дает достаточно полную картину широких возможностей, имеющихся при работе со строками в C#. Следует помнить, что класс string является неизменяемым. Поэтому Replace, Insert и другие методы представляют собой функции, возвращающие новую строку в качестве результата и не изменяющие строку, вызвавшую метод.
|
Таблица 14.2. Динамические методы и свойства класса String |
|
|
Метод |
Описание |
| Insert | Вставляет подстроку в заданную позицию |
| Remove | Удаляет подстроку в заданной позиции |
| Replace | Заменяет подстроку в заданной позиции на новую подстроку |
| Substring | Выделяет подстроку в заданной позиции |
| IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny | Определяются индексы первого и последнего вхождения заданной подстроки или любого символа из заданного набора |
| StartsWith, EndsWith | Возвращается true или false, в зависимости от того, начинается или заканчивается строка заданной подстрокой |
| PadLeft, PadRight | Выполняет набивку нужным числом пробелов в начале и в конце строки |
| Trim, TrimStart, TrimEnd | Обратные операции к методам Pad. Удаляются пробелы в начале и в конце строки, или только с одного ее конца |
| ToCharArray | Преобразование строки в массив символов |
Tags: CompareOrdinal, Concat, Console, Copy, CultureInfo, Format, Globalization, IFormatProvider, int, Intern, Percent, string, StringBuilder, System, TestFormat, WriteLine
Находится в Учебник | No Comments »
Ответить
Вы должны быть в системе, дабы комментировать.
