Символы и строки
Обработка текстовой информации является одной из самых распространенных задач современного программировании. С# предоставляет для ее решения широкий набор средств: символы char, неизменяемые строки string, изменяемые строки StringBuider и регулярные выражения Regex. В данном разделе мы рассмотрим работу с символами, неизменяемыми и изменяемыми строками.
Символы char
Символьный тип char предназначен для хранения символа в кодировке Unicode. Символьный тип относится к встроенным типам данных С# и соответствует стандартному классу Сhar библиотеки .Net из пространства имен System. В этом классе определены статические методы, позволяющие задавать вид и категорию символа, а также преобразовывать символ в верхний или нижний регистр, в число. Рассмотрим основные методы:
Метод | Описание |
---|---|
GetNumericValue | Возвращает числовое значение символа, если он является цифрой, и -1 в противном случае. |
GetUnicodeCategory | Возвращает категорию Unicode-символа. В Unicode символы разделены на категории, например цифры ( DecimalDigitNumber ), римские цифры ( LetterNumber ), разделители строк ( LineSeparator ), буквы в нижнем регистре ( LowercaseLetter ) и т.д. |
IsControl | Возвращает true, если символ является управляющим. |
IsDigit | Возвращает true, если символ является десятичной цифрой. |
IsLetter | Возвращает true, если символ является буквой. |
IsLetterOrDigit | Возвращает true, если символ является буквой или десятичной цифрой. |
IsLower | Возвращает true, если символ задан в нижнем регистре. |
IsNumber | Возвращает true, если символ является числом (десятичным или шестнадцатеричным). |
IsPunctuation | Возвращает true, если символ является знаком препинания. |
IsSeparator | Возвращает true, если символ является разделителем. |
IsUpper | Возвращает true, если символ задан в верхнем регистре. |
IsWhiteSpace | Возвращает true, если символ является пробельным (пробел, перевод строки, возврат каретки). |
Parse | Преобразует строку в символ (строка должна состоять из одного символа). |
ToLower | Преобразует символ в нижний регистр |
ToUpper | Преобразует символ в верхний регистр |
В следующем примере рассмотрим применение данных методов:
static void Main() { try { char b = 'B', c = '\x64', d = '\uffff'; Console.WriteLine("{0}, {1}, {2}", b, c, d); Console.WriteLine("{0}, {1}, {2}", char.ToLower(b), char.ToUpper(c), char.GetNumericValue(d)); char a; do //цикл выполнятеся до тех пор, пока не ввели символ e { Console.WriteLine("Введите символ: "); a = char.Parse(Console.ReadLine()); Console.WriteLine("Введен символ {0}, его код {1}, его категория {2}", a, (int)a, char.GetUnicodeCategory(a)); if (char.IsLetter(a)) Console.WriteLine("Буква"); if (char.IsUpper(a)) Console.WriteLine("Верхний регистр"); if (char.IsLower(a)) Console.WriteLine("Нижний регистр"); if (char.IsControl(a)) Console.WriteLine("Управляющий символ"); if (char.IsNumber(a)) Console.WriteLine("Число"); if (char.IsPunctuation(a)) Console.WriteLine("Разделитель"); } while (a != 'e'); } catch { Console.WriteLine("Возникло исключение"); } }
Используя символьный тип можно оргранизовать массив символов и работать с ним на основе базового класса Array:
static void Main() { char[] a ={ 'm', 'a', 'Х', 'i', 'M', 'u', 'S' , '!', '!', '!' }; char [] b="кол около колокола".ToCharArray(); //преобразование строки в массив символов PrintArray("Исходный массив а:", a); for (int x=0;x<a.Length; x++) if (char.IsLower(a[x])) a[x]=char.ToUpper(a[x]); PrintArray("Измененный массив а:", a); PrintArray("Исходный массив b:", b); Array.Reverse(b); PrintArray("Измененный массив b:", b); } static void PrintArray(string line, Array a) { Console.WriteLine(line); foreach( object x in a) Console.Write(x); Console.WriteLine('\n'); }
Неизменяемые строки string
Тип string, предназначенный для работы со строками символов в кодировке Unicode, является встроенным типом С#. Ему соответствует базовый тип класса System.String библиотеки .Net. Каждый объект string - это неизменяемая последовательность символов Unicode, т.е. методы, предназначенные для изменения строк, возвращают измененные копии, исходные же строки остаются неизменными.
Создать строку можно несколькими способами:
-
string s; // инициализация отложена
-
string s=''кол около колокола''; //инициализация строковым литералом
-
string s=@'Привет!' //символ @ сообщает конструктору string, что строку Сегодня хорошая погода!!! '' // нужно воспринимать буквально, даже если она занимает //несколько строк
-
string s=new string (' ', 20); //конструктор создает строку из 20 пробелов
-
int x = 12344556; //инициализировали целочисленную переменную string s = x.ToString(); //преобразовали ее к типу string
-
char [] a={'a', 'b', 'c', 'd', 'e'}; //создали массив символов string v=new string (a); // создание строки из массива символов
-
char [] a={'a', 'b', 'c', 'd', 'e'}; // создание строки из части массива символов, при этом: 0 string v=new string (a, 0, 2) // показывает с какого символа, 2 - сколько символов // использовать для инициализации
Класс string обладает богатым набором методов для сравнения строк, поиска в строке и других действий со строками. Рассмотрим эти методы.
Напоминаем, что вызов статических методов происходит через обращение к имени класса, например, String.Concat(str1, str2), в остальных случаях через обращение к экземплярам класса, например, str.ToLower(). На примере рассмотрим использование данных свойств и методов.
static void Main() { string str1 ="Первая строка"; string str2 = string.Copy(str1); string str3 = "Вторая строка"; string str4 = "ВТОРАЯ строка"; string strUp, strLow; int result, idx; Console.WriteLine("str1: " + str1); Console.WriteLine("Длина строки str1: " +str1.Length); // Создаем прописную и строчную версии строки str1. strLow = str1.ToLower(); strUp = str1.ToUpper(); Console.WriteLine("Строчная версия строки str1: " +strLow); Console.WriteLine("Прописная версия строки str1: " +strUp); Console.WriteLine(); // Сравниваем строки, result = str1.CompareTo(str3); if (result == 0) Console.WriteLine("str1 и str3 равны."); else if (result < 0) Console.WriteLine("str1 меньше, чем str3"); else Console.WriteLine("str1 больше, чем str3"); Console.WriteLine(); //сравниваем строки без учета регистра result = String.Compare(str3,str4,true); if (result == 0) Console.WriteLine("str3 и str4 равны без учета регистра."); else Console.WriteLine("str3 и str4 не равны без учета регистра."); Console.WriteLine(); //сравниваем части строк result = String.Compare(str1, 4, str2, 4, 2); if (result == 0) Console.WriteLine("часть str1 и str2 равны"); else Console.WriteLine("часть str1 и str2 не равны"); Console.WriteLine(); // Поиск строк. idx = str2.IndexOf("строка"); Console.WriteLine("Индекс первого вхождения подстроки строка: " + idx); idx = str2.LastIndexOf("о"); Console.WriteLine("Индекс последнего вхождения символа о: " + idx); //конкатенация string str=String.Concat(str1, str2, str3, str4); Console.WriteLine(str); //удаление подстроки str=str.Remove(0,str1.Length); Console.WriteLine(str); //замена подстроки "строка" на пустую подстроку str=str.Replace("строка",""); Console.WriteLine(str); }
Очень важными методами обработки строк, являются методы разделения строки на элементы Split и слияние массива строк в единую строку Join.
static void Main() { string poems = "тучки небесные вечные странники"; char[] div = { ' '}; //создаем массив разделителей // Разбиваем строку на части, string[] parts = poems.Split(div); Console.WriteLine("Результат разбиения строки на части: "); for (int i = 0; i < parts.Length; i++) Console.WriteLine(parts[i]); // Теперь собираем эти части в одну строку, в качестве разделителя используем символ | string whole = String.Join(" | ", parts); Console.WriteLine("Результат сборки: "); Console.WriteLine(whole); }
В общем случае строка может содержать и другие разделители:
static void Main() { string poems = "Тучки небесные, вечные странники..."; char[] div = { ' ', ',', '.'}; //создаем массив разделителей // Разбиваем строку на части, string[] parts = poems.Split(div); Console.WriteLine("Результат разбиения строки на части: "); for (int i = 0; i < parts.Length; i++) Console.WriteLine(parts[i]); // Теперь собираем эти части в одну строку, string whole = String.Join(" | ", parts); Console.WriteLine("Результат сборки: "); Console.WriteLine(whole); }
- Объясните, почему в массиве строк parts появились пустые строки.
- Внесите изменения в программу так, чтобы пустых строк не было.
Рассмотрим другой пример - используя метод Split вводить двумерный массив можно не поэлементно, а построчно:
static void Main() { try { int[][] MyArray; Console.Write("введите количество строк: "); int n = int.Parse(Console.ReadLine()); MyArray = new int[n][]; for (int i = 0; i < MyArray.Length; i++) { string line = Console.ReadLine(); string[] mas = line.Split(' '); MyArray[i] = new int[mas.Length]; for (int j = 0; j < MyArray[i].Length; j++) { MyArray[i][j] = int.Parse(mas[j]); } } PrintArray("исходный массив:", MyArray); for (int i = 0; i < MyArray.Length; i++) Array.Sort(MyArray[i]); PrintArray("итоговый массив", MyArray); } catch { Console.WriteLine("возникло исключение"); } } static void PrintArray(string a, int[][] mas) { Console.WriteLine(a); for (int i = 0; i < mas.Length; i++) { foreach (int x in mas[i]) Console.Write("{0} ", x); Console.WriteLine(); } }
В этом примере могут возникнуть исключительные ситуации, если введенная строка элементов массива будет содержать лишние пробелы. Следовательно, от этих пробелов нужно избавиться:
static void Main() { try { int[][] MyArray; Console.Write("введите количество строк: "); string line= Console.ReadLine() int n = int.Parse(line.Trim()); MyArray = new int[n][]; for (int i = 0; i < MyArray.Length; i++) { line = Console.ReadLine(); line=line.Trim(); //удалаяем пробелы в начале и конце строки //удаляем линшие пробелы внутри строки n = line.IndexOf(" "); while (n > 0) { line = line.Remove(n, 1); n = line.IndexOf(" "); } string[] mas = line.Split(' '); MyArray[i] = new int[mas.Length]; for (int j = 0; j < MyArray[i].Length; j++) { MyArray[i][j] = int.Parse(mas[j]); } } PrintArray("исходный массив:", MyArray); for (int i = 0; i < MyArray.Length; i++) Array.Sort(MyArray[i]); PrintArray("итоговый массив", MyArray); } catch { Console.WriteLine("возникло исключение"); } } static void PrintArray(string a, int[][] mas) { Console.WriteLine(a); for (int i = 0; i < mas.Length; i++) { foreach (int x in mas[i]) Console.Write("{0} ", x); Console.WriteLine(); } }
При работе с объектами класса string нужно учитывать их свойство неизменяемости, т.е. тот факт, что методы изменяют не сами строки, а их копии. Рассмотрим фрагмент программы:
string a=""; for (int i = 1; i <= 100; i++) a +="!"; Console.WriteLine(a);
В этом случае в памяти компьютера будет сформировано 100 различных строк вида:
! !! !!! … !!!...!!
И только последняя строка будет храниться в переменной а. Ссылки на все остальные строчки будут потеряны, но эти строки будут храниться в памяти компьютера и засорять память. Бороться с таким засорением придется сборщику мусора, что будет сказываться на производительности программы. Поэтому если нужно изменять строку, то лучше пользоваться классом StringBuilder.