Читать в оригинале

<< Предыдущая Оглавление Следующая >>


8.3.3. Операции над строками

Над строками определены следующие операции:

- присваивание (=);

- две операции проверки эквивалентности (= =) и (!=);

- конкатенация или сцепление строк (+);

- взятие индекса ([]).

Начнем с присваивания, имеющего важную особенность. Поскольку 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';
}

Статические методы класса String

Сводка статических методов класса String приводится в таблице 6.

Таблица 6. Статические методы класса String

Метод

Описание

Empty

Возвращается пустая строка. Свойство со статусом read only

Compare

Сравнение двух строк. Метод перегружен. Реализации метода позволяют сравнивать как строки, так и подстроки. При этом можно учитывать или не учитывать регистр, особенности национального форматирования дат, чисел и т.д.

CompareOrdinal

Сравнение двух строк. Метод перегружен. Реализации метода позволяют сравнивать как строки, так и подстроки. Сравниваются коды символов

Concat

Конкатенация строк. Метод перегружен, допускает сцепление произвольного числа строк

Copy

Создается копия строки

Format

Выполняет форматирование в соответствии с заданными спецификациями формата. Ниже приведено более полное описание метода

Intern, Islntern

Отыскивается и возвращается ссылка на строку, если таковая уже хранится во внутреннем пуле данных. Если же строки нет, то первый из методов добавляет строку во внутренний пул, второй - возвращает null. Методы применяются обычно тогда, когда строка создается с использованием построителя строк - класса StringBuilder

Join

Конкатенация массива строк в единую строку. При конкатенации между элементами массива вставляются разделители. Операция, заданная методом Join, является обратной к операции, заданной методом Split. Последний является динамическим методом и, используя разделители, осуществляет разделение строки на элементы

Методы 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

Результаты выполнения этой процедуры показаны на рис. 30.

Рисунок 30. Разбор и сборка строки текста

Обратите внимание, что методы Split и Join хорошо работают, когда при разборе используется только один разделитель. В этом случае сборка действительно является обратной операцией и позволяет восстановить исходную строку. Если же при разборе задается некоторое множество разделителей, то возникают две проблемы:

1. Невозможно при сборке восстановить строку в прежнем виде, поскольку не сохраняется информация о том, какой из разделителей был использован при разборе строки. Поэтому при сборке между элементами вставляется один разделитель, возможно, состоящий из нескольких символов;

2. При разборе двух подряд идущих разделителей предполагается, что между ними находится пустое слово. Обратите внимание в тексте нашего примера, как и положено, после запятой следует пробел. При разборе текста на слова в качестве разделителей указаны символы пробела и запятой. По этой причине в массиве слов, полученном в результате разбора, имеются пустые слова.

Если при разборе предложения на слова использовать в качестве разделителя только пробел, то пустые слова не появятся, но запятая будет являться частью некоторых слов.

Как всегда, есть несколько способов справиться с проблемой. Один из них состоит в том, чтобы написать собственную реализацию этих функций, другой - в корректировке полученных результатов, третий - в использовании более мощного аппарата регулярных выражений.

Динамические методы класса String

Операции, разрешенные над строками в C#, разнообразны. Методы этого класса позволяют выполнять вставку, удаление, замену, поиск вхождения подстроки в строку. Класс String наследует методы класса Object, частично их переопределяя. Класс String наследует и, следовательно, реализует методы четырех интерфейсов: ICompareable, ICloneable, IConvertible, Enumerable. Три из них уже рассматривались при описании классов-массивов.

Рассмотрим наиболее характерные методы при работе со строками.

Сводка методов, приведенная в таблице 7, дает достаточно полную картину широких возможностей, имеющихся при работе со строками в C#. Следует помнить, что класс string является неизменяемым. Поэтому Replace, Insert и другие методы представляют собой функции, возвращающие новую строку в качестве результата и не изменяющие строку, вызвавшую метод.

Таблица 7. Динамические методы класса String

Метод

Описание

Insert

Вставляет подстроку в заданную позицию

Remove

Удаляет подстроку в заданной позиции

Replace

Заменяет подстроку в заданной позиции на новую подстроку

Substring

Выделяет подстроку в заданной позиции

IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny

Определяются индексы первого и последнего вхождения заданной подстроки или любого символа из заданного набора

StartsWith, EndsWith

Возвращается true или false, в зависимости от того, начинается или заканчивается строка заданной подстрокой

PadLeft, PadRight

Выполняет набивку нужным числом пробелов в начале и в конце строки

Trim,TrimStart, TrimEnd

Обратные операции к методам Pad. Удаляются пробелы в начале и в конце строки, или только с одного ее конца

ToCharArray

Преобразование строки в массив символов

 



<< Предыдущая Оглавление Следующая >>