Студопедия

Главная страница Случайная страница

КАТЕГОРИИ:

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Класс char[] - массив символов






В языке C# определен класс Char[], и его можно использовать для представления строк постоянной длины, как это делается в С++. Более того, поскольку массивы в C# динамические, то расширяется класс задач, в которых можно использовать массивы символов для представления строк. Так что имеет смысл разобраться, насколько хорошо C# поддерживает работу с таким представлением строк.

Прежде всего, ответим на вопрос, задает ли массив символов C# строку С, заканчивающуюся нулем? Ответ: нет, не задает. Массив char[] - это обычный массив. Более того, его нельзя инициализировать строкой символов, как это разрешается в С++. Константа, задающая строку символов, принадлежит классу String, а в C# не определены взаимные преобразования между классами String и Char[], даже явные. У класса String есть, правда, динамический метод ToCharArray, задающий подобное преобразование. Возможно также посимвольно передать содержимое переменной string в массив символов. Приведу пример:

public void TestCharArAndString(){ //массивы символов //char[] strM1 = " Hello, World! "; //ошибка: нет преобразования класса string в класс char[] string hello = " Здравствуй, Мир! "; char[] strM1 = hello.ToCharArray(); PrintCharAr(" strM1", strM1); //копирование подстроки char[] World = new char[3]; Array.Copy(strM1, 12, World, 0, 3); PrintCharAr(" World", World); Console.WriteLine(CharArrayToString(World)); }//TestCharArAndString

Закомментированные операторы в начале этой процедуры показывают, что прямое присваивание строки массиву символов недопустимо. Однако метод ToCharArray, которым обладают строки, позволяет легко преодолеть эту трудность. Еще одну возможность преобразования строки в массив символов предоставляет статический метод Copy класса Array.

В нашем примере часть строки strM1 копируется в массив World. По ходу дела в методе вызывается процедура PrintCharAr класса Testing, печатающая массив символов как строку. Вот ее текст:

void PrintCharAr(string name, char[] ar){ Console.WriteLine(name); for(int i=0; i < ar.Length; i++) Console.Write(ar[i]); Console.WriteLine(); }//PrintCharAr

Метод ToCharArray позволяет преобразовать строку в массив символов. К сожалению, обратная операция не определена, поскольку метод ToString, которым, конечно же, обладают все объекты класса Char[], печатает информацию о классе, а не содержимое массива. Ситуацию легко исправить, написав подходящую процедуру. Вот текст этой процедуры CharArrayToString, вызываемой в нашем тестирующем примере:

string CharArrayToString(char[] ar){ string result=" "; for(int i = 0; i< ar.Length; i++) result += ar[i]; return(result); }//CharArrayToString

Класс Char[], как и всякий класс-массив в C#, является наследником не только класса Object, но и класса Array, и, следовательно, обладает всеми методами родительских классов, подробно рассмотренных в предыдущей главе. А есть ли у него специфические методы, которые позволяют выполнять операции над строками, представленными массивами символов? Таких специальных операций нет. Но некоторые перегруженные методы класса Array можно рассматривать как операции над строками. Например, метод Copy дает возможность выделять и заменять подстроку в теле строки. Методы IndexOf, LastIndexOf позволяют определить индексы первого и последнего вхождения в строку некоторого символа. К сожалению, их нельзя использовать для более интересной операции - нахождения индекса вхождения подстроки в строку. При необходимости такую процедуру можно написать самому. Вот как она выглядит:

int IndexOfStr(char[]s1, char[] s2){ //возвращает индекс первого вхождения подстроки s2 в //строку s1 int i =0, j=0, n=s1.Length-s2.Length; bool found = false; while((i< =n) & &! found) { j = Array.IndexOf(s1, s2[0], i); if (j < = n) { found=true; int k = 0; while ((k < s2.Length)& & found) { found =char.Equals(s1[k+j], s2[k]); k++; } } i=j+1; } if(found) return(j); else return(-1); }//IndexOfStr

В реализации используется метод IndexOf класса Array, позволяющий найти начало совпадения строк, после чего проверяется совпадение остальных символов. Реализованный здесь алгоритм является самым очевидным, но далеко не самым эффективным.

А теперь рассмотрим процедуру, в которой определяются индексы вхождения символов и подстрок в строку:

public void TestIndexSym(){ char[] str1, str2; str1 = " рококо".ToCharArray(); //определение вхождения символа int find, lind; find= Array.IndexOf(str1, 'о'); lind = Array.LastIndexOf(str1, 'о'); Console.WriteLine(" Индексы вхождения о в рококо: {0}, {1}; ", find, lind); //определение вхождения подстроки str2 = " рок".ToCharArray(); find = IndexOfStr(str1, str2); Console.WriteLine(" Индекс первого вхождения рок в рококо: {0}", find); str2 = " око".ToCharArray(); find = IndexOfStr(str1, str2); Console.WriteLine(" Индекс первого вхождения око в рококо: {0}", find); }//TestIndexSym

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


Рис. 13.3. Индексы вхождения подстроки в строку

Существует ли в C# тип char*

В языке C# указатели допускаются в блоках, отмеченных как небезопасные. Теоретически в таких блоках можно объявить переменную типа Char*, но все равно не удастся написать столь же короткую, как в С++, процедуру копирования строк. Правильно считать, что в C# строки типа char* использовать не рекомендуется.

Класс 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. Последний является динамическим методом и, используя разделители, осуществляет разделение строки на элементы

Поделиться с друзьями:

mylektsii.su - Мои Лекции - 2015-2024 год. (0.008 сек.)Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав Пожаловаться на материал