русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

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


Дата добавления: 2013-12-23; просмотров: 2065; Нарушение авторских прав


Объявление строк. Конструкторы класса string

Класс String

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

Статические методы и свойства класса Char

Класс char

Класс Object и массивы

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

Приведу в качестве примера процедуру печати объектов. На этот раз формальный аргумент процедуры будет иметь тип оbject - прародителя всех классов. Разберем, как можно выяснить, что в процедуру передается массив, как определить его тип и работать с ним уже как с массивом, а не как с переменной класса Object. Вот текст этой процедуры, названной PrintObject:

 

public static void PrintObj(object A) {

Console.WriteLine("A.GetType()={0})", A.GetType());

if (A.GetType()==typeof(System.Int32[])) {

int[] temp;

temp = (int[])A;

for(int i = 0; i<temp.GetLength(0);i++)

Console.Write("\t temp[{0}]={1}", i,temp[i]);

Console.WriteLine();

}

else

Console.WriteLine("Аргумент не является массивом целых");

}//PrintObject

Метод GetType, примененный к аргументу, возвращает не тип Object, а реальный тип фактического аргумента. Поэтому можно проанализировать, какому классу принадлежит объект, переданный в процедуру.

На каждой ветви разбора можно создать временный объект нужного типа и скопировать в него переданный аргумент. В данном примере рассматривается только одна ветвь, в которой создается целочисленный одномерный массив temp.



Заметьте, при присваивании значения переменной temp выполняется явное преобразование из класса Object в класс Int[].

При наличии переменной temp, выполнение нужных действий над массивом не представляет никаких трудностей.

Приведу два примера вызова этой процедуры:

 

//работа с процедурой PrintObject

//Корректный и некорректный вызовы

Arrs.PrintObj(col1);

Arrs.PrintObj(col3);

Строки в С#

Когда говорят о строковом типе, то обычно различают тип, представляющий:

· отдельные символы, чаще всего, его называют типом char;

· строки постоянной длины, часто они представляются массивом символов;

· строки переменной длины - это, как правило, тип string, соответствующий современному представлению о строковом типе.

 

В C# есть символьный класс Char, основанный на классе System.Char и использующий двухбайтную кодировку Unicode представления символов. Для этого типа в языке определены символьные константы - символьные литералы. Константу можно задавать:

· символом, заключенным в одинарные кавычки;

· escape-последовательностью, задающей код символа;

· Unicode-последовательностью, задающей Unicode-код символа.

Вот несколько примеров объявления символьных переменных и работы с ними:

 

public void TestChar(){

char ch1='A', ch2 ='\x5A', ch3='\u0058';

char ch = new Char();

int code; string s;

ch = ch1;

//преобразование символьного типа в тип int

code = ch; ch1=(char) (code +1);

//преобразование символьного типа в строку

//s = ch;

s = ch1.ToString()+ch2.ToString()+ch3.ToString();

Console.WriteLine("s= {0}, ch= {1}, code = {2}",

s, ch, code);

}

Три символьные переменные инициализированы константами, значения которых заданы тремя разными способами. Переменная ch объявляется в объектном стиле, используя new и вызов конструктора класса. Тип char, как и все типы C#, является классом. Этот класс наследует свойства и методы класса Object и имеет большое число собственных методов.

Существуют ли преобразования между классом char и другими классами? Явные или неявные преобразования между классами char и string отсутствуют, но, благодаря методу ToString, переменные типа char стандартным образом преобразуются в тип string.

В результате работы процедуры TestChar строка s, полученная сцеплением трех символов, преобразованных в строки, имеет значение BZX, переменная ch равна A, а ее код - переменная code - 65.

Не раз отмечалось, что семантика присваивания справедлива при вызове методов и замене формальных аргументов на фактические. Приведу две процедуры, выполняющие взаимно-обратные операции - получение по коду символа и получение символа по его коду:

 

public int SayCode(char sym){

return (sym);

}

public char SaySym(object code){

return ((char)((int)code));

}

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

Метод Описание
GetNumericValue Возвращает численное значение символа, если он является цифрой, и (-1) в противном случае
IsDigit Возвращает true, если символ является десятичной цифрой
IsLetter Возвращает true, если символ является буквой
IsLetterOrDigit Возвращает true, если символ является буквой или цифрой
IsLower Возвращает true, если символ задан в нижнем регистре
IsNumber Возвращает true, если символ является числом (десятичной или шестнадцатиричной цифрой)
IsUpper Возвращает true, если символ задан в верхнем регистре
ToLower Приводит символ к нижнему регистру
ToUpper Приводит символ к верхнему регистру

 

Класс Char, как и все классы в C#, наследует свойства и методы родительского класса Object.

bool IsControl(char ch)

bool IsControl(string str, int ilndex)

bool IsSeparator(char ch) – знак пробел

bool IsSeparator(string str, int ilndex)

bool IsWhiteSpace(char ch)

bool IsWhiteSpace(string str, int ilndex)

bool IsPunctuation(char ch) – знак пунктуации

bool IsPunctuation(string str, int ilndex)

bool IsSymbol(char ch) - символ

bool IsSymbol(string str, int ilndex)

bool IsDigit(char ch) – цифрофой символ

bool IsDigit(string str, int ilndex)

bool IsNumber(char ch) - число

bool IsNumber(string str, int ilndex)

bool IsLetter(char ch) - буква

bool IsLetter(string str, int ilndex)

bool IsUpper(char ch)- символ в верхнем регистре

bool IsUpper(string str, int ilndex)

bool IsLower(char ch)- )- символ в нижнем регистре

bool IsLower(string str, int ilndex)

bool IsLetterOrDigit(char ch) – символ или цифра

bool IsLetterOrDigit(string str, int ilndex)

bool IsSurrogate(char ch)

bool IsSurrogate(string str, int ilndex)

Вызов: Char.IsControl(str[ilndex]) эквивалентен:

Char. IsControl(str, ilndex)

 

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

 

public void TestCharMethods() {

Console.WriteLine("Статические методы класса char:");

char ch='a', ch1='1', lim =';', chc='\xA';

double d1, d2;

d1=char.GetNumericValue(ch); d2=char.GetNumericValue(ch1);

Console.WriteLine("Метод GetNumericValue:");

Console.WriteLine("sym 'a' - value {0}", d1);

Console.WriteLine("sym '1' - value {0}", d2);

System.Globalization.UnicodeCategory cat1, cat2;

cat1 =char.GetUnicodeCategory(ch1);

cat2 =char.GetUnicodeCategory(lim);

Console.WriteLine("Метод GetUnicodeCategory:");

Console.WriteLine("sym '1' - category {0}", cat1);

Console.WriteLine("sym ';' - category {0}", cat2);

Console.WriteLine("Метод IsControl:");

Console.WriteLine("sym '\xA' - IsControl - {0}", char.IsControl(chc));

Console.WriteLine("sym ';' - IsControl - {0}", char.IsControl(lim));

Console.WriteLine("Метод IsSeparator:");

Console.WriteLine("sym ' ' - IsSeparator - {0}", char.IsSeparator(' '));

Console.WriteLine("sym ';' - IsSeparator - {0}", char.IsSeparator(lim));

Console.WriteLine("Метод IsSurrogate:");

Console.WriteLine("sym '\u10FF' - IsSurrogate - {0}", char.IsSurrogate('\u10FF'));

Console.WriteLine("sym '\\' - IsSurrogate - {0}", char.IsSurrogate('\\'));

string str = "\U00010F00";

//Символы Unicode в интервале [0x10000,0x10FFF]

//представляются двумя 16-битными суррогатными символами

Console.WriteLine("str = {0}, str[0] = {1}", str, str[0]);

Console.WriteLine("str[0] IsSurrogate - {0}",

char.IsSurrogate(str, 0));

Console.WriteLine("Метод IsWhiteSpace:");

str ="пробелы, пробелы!" + "\xD" + "\xA" + "Всюду пробелы!";

Console.WriteLine("sym '\xD ' - IsWhiteSpace - {0}",

char.IsWhiteSpace('\xD'));

Console.WriteLine("str: {0}", str);

Console.WriteLine("и ее пробелы - символ 8 {0},символ 17 {1}",

char.IsWhiteSpace(str,8), char.IsWhiteSpace(str,17));

Console.WriteLine("Метод Parse:");

str="A";

ch = char.Parse(str);

Console.WriteLine("str:{0} char: {1}",str, ch);

Console.WriteLine("Минимальное и максимальное значение:{0}, {1}",

char.MinValue.ToString(), char.MaxValue.ToString());

Console.WriteLine("Их коды: {0}, {1}",

SayCode(char.MinValue), SayCode(char.MaxValue));

}//TestCharMethods

 

Кроме статических методов, у класса Char есть и динамические. Большинство из них - это методы родительского класса Object, унаследованные и переопределенные в классе Char. Из собственных динамических методов стоит отметить метод CompareTo, позволяющий проводить сравнение символов. Он отличается от метода Equal тем, что для несовпадающих символов выдает "расстояние" между символами в соответствии с их упорядоченностью в кодировке Unicode. Приведу пример:

 

public void testCompareChars(){

char ch1, ch2;

int dif;

Console.WriteLine("Метод CompareTo");

ch1='A'; ch2= 'Z';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Расстояние между символами {0},

{1} = {2}", ch1, ch2, dif); //-25

ch1='а'; ch2= 'А';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Расстояние между символами {0},

{1} = {2}", ch1, ch2, dif); //32

ch1='Я'; ch2= 'А';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Расстояние между символами {0},

{1} = {2}", ch1, ch2, dif); //31

ch1='A'; ch2= 'A';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Расстояние между символами {0},

{1} = {2}", ch1, ch2, dif); //0

ch1='А'; ch2= 'A';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Расстояние между символами {0},

{1} = {2}", ch1, ch2, dif); //975

ch1='Ё'; ch2= 'А';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Расстояние между символами {0},

{1} = {2}", ch1, ch2, dif); //-15

}//TestCompareChars

Анализируя эти результаты, можно понять, что в кодировке Unicode как латиница, так и кириллица плотно упакованы. Исключение составляет буква Ё - заглавная и малая - они выпадают из плотной кодировки. Малые буквы в кодировке непосредственно следуют за заглавными буквами. Расстояние между алфавитами в кодировке довольно большое - русская буква А на 975 символов правее в кодировке, чем соответствующая буква в латинском алфавите.

 

В языке 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));

}

Закомментированные операторы в начале этой процедуры показывают, что прямое присваивание строки массиву символов недопустимо. Однако метод 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();

}

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

 

string CharArrayToString(char[] ar){

string result="";

for(int i = 0; i< ar.Length; i++) result += ar[i];

return(result);

}

Класс 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);

}

В реализации используется метод 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);

}

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

Правильно считать, что в C# строки типа char* использовать не рекомендуется.

Основным типом при работе со строками является тип string, задающий строки переменной длины. Класс String в языке C# относится к ссылочным типам. Над строками - объектами этого класса - определен широкий набор операций, соответствующий современному представлению о том, как должен быть устроен строковый тип.

Объекты класса String объявляются как все прочие объекты простых типов - с явной или отложенной инициализацией, с явным или неявным вызовом конструктора класса. Чаще всего, при объявлении строковой переменной конструктор явно не вызывается, а инициализация задается строковой константой. Но у класса Sring достаточно много конструкторов. Они позволяют сконструировать строку из:

· символа, повторенного заданное число раз;

· массива символов char[];

· части массива символов.

String(char ch, int iCount);

String(char[] ach);

String(char[] ach, Int iStartlndex, int iCount);

 

Приведу примеры объявления строк с вызовом разных конструкторов:

 

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';

}

 



<== предыдущая лекция | следующая лекция ==>
Массивы как коллекции | Описание некоторых методов


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.014 сек.