Неизменяемые строки string
Символы и строки Лекция рассматривает символы и строки: типы данных char, string. Также рассмотрены изменяемые строки.
Обработка текстовой информации является одной из самых распространенных задач современного программировании. С# предоставляет для ее решения широкий набор средств: символы 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');}Задание. Измените программу так, чтобы в ней подсчитывалось количество знаков пунктуации в массиве a.
static void Main()
{
char[] a = { 'm', 'a', 'Х', 'i', 'M', 'u', 'S', '!', '!', '!', ',', '.'};
PrintArray("Исходный массив а:", a);
int t = 0;
for (int x = 0; x < a.Length; x++)
if (char.IsPunctuation(a[x])) { ++t; }
Console.WriteLine(t);
// if (char.IsLower(a[x])) a[x] = char.ToUpper(a[x]);
Console.Read();
}
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, т.е. методы, предназначенные для изменения строк, возвращают измененные копии, исходные же строки остаются неизменными.
Создать строку можно несколькими способами:
1. string s; // инициализация отложена2. string s=''кол около колокола''; //инициализация строковым литералом3. string s=@'Привет!' //символ @ сообщает конструктору string, что строку 4. Сегодня хорошая погода!!! '' // нужно воспринимать буквально, даже если она занимает 5. //несколько строкКласс string обладает богатым набором методов для сравнения строк, поиска в строке и других действий со строками. Рассмотрим эти методы.
Название | Вид | Описание |
Compare | Статический метод | Сравнение двух строк в лексикографическом (алфавитном) порядке. Разные реализации метода позволяют сравнивать строки с учетом или без учета регистра. |
CompareTo | Метод | Сравнение текущего экземпляра строки с другой строкой. |
Concat | Статический метод | Слияние произвольного числа строк. |
Copy | Статический метод | Создание копии строки |
Empty | Статическое поле | Открытое статическое поле, представляющее пустую строку |
Format | Статический метод | Форматирование строки в соответствии с заданным форматом |
IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny | Экземплярные методы | Определение индексов первого и последнего вхождения заданной подстроки или любого символа из заданного набора в данную строку. |
Insert | Экземплярный метод | Вставка подстроки в заданную позицию |
Join | Статический метод | Слияние массива строк в единую строку. Между элементами массива вставляются разделители. |
Length | Свойство | Возвращает длину строки |
PadLeft, PadRigth | Экземплярные методы | Выравнивают строки по левому или правому краю путем вставки нужного числа пробелов в начале или в конце строки. |
Remove | Экземплярный метод | Удаление подстроки из заданной позиции |
Replace | Экземплярный метод | Замена всех вхождений заданной подстроки или символа новыми подстрокой или символом. |
Split | Экземплярный метод | Разделяет строку на элементы, используя разные разделители. Результаты помещаются в массив строк. |
StartWith, EndWith | Экземплярные методы | Возвращают true или false в зависимости от того, начинается или заканчивается строка заданной подстрокой. |
Substring | Экземплярный метод | Выделение подстроки, начиная с заданной позиции |
ToCharArray | Экземплярный метод | Преобразует строку в массив символов |
ToLower, ToUpper | Экземплярные методы | Преобразование строки к нижнему или верхнему регистру |
Trim, TrimStart, TrimEnd | Экземплярные методы | Удаление пробелов в начале и конце строки или только с одного ее конца. |
Напоминаем, что вызов статических методов происходит через обращение к имени класса, например, 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(); }}Задание. Объясните, можно ли удалить внутри строки лишние пробелы, используя метод Replace. Например, следующим способом str.Replace(" ", " "), где мы пытаемся заменить подстроку состоящую из двух, на подстроку из одиного пробела.
При работе с объектами класса string нужно учитывать их свойство неизменяемости, т.е. тот факт, что методы изменяют не сами строки, а их копии. Рассмотрим фрагмент программы:
string a=""; for (int i = 1; i <= 100; i++) a +="!"; Console.WriteLine(a);В этом случае в памяти компьютера будет сформировано 100 различных строк вида:
!!!!!!…!!!...!!И только последняя строка будет храниться в переменной а. Ссылки на все остальные строчки будут потеряны, но эти строки будут храниться в памяти компьютера и засорять память. Боротся с таким засорением придется сборщику мусора, что будет сказываться на производительности программы. Поэтому если нужно изменять строку, то лучше пользоваться классом StringBuilder.
Изменяемые строки
Чтобы создать строку, которую можно изменять, в С# предусмотрен класс StringBuilder, определенный в пространстве имен System.Text. Объекты этого класса всегда объявляются с явным вызовом конструктора класса (через операцию new) . Примеры создания изменяемых строк:
StringBuilder a =new StringBuilder(); //создание пустой строки, размер по умолчанию 16 символов//инициализация строки и выделение необходимой памятиStringBuilder b = new StringBuilder("abcd"); //создание пустой строки и выделение памяти под 100 символовStringBuilder с = new StringBuilder(100);//инициализация строки и выделение памяти под 100 символов StringBuilder d = new StringBuilder("abcd", 100);//инициализация подстрокой "bcd", и выделение памяти под 100 символов StringBuilder d = new StringBuilder("abcd", 1, 3,100);Основные элементы класса приведены в таблице:
Название | Вид | Описание |
Append | Экземплярный метод | Добавление данных в конец строки. Разные варианты метода позволяют добавлять в строку величины любых встроенных типов, массивы символов, строки и подстроки string. |
AppendFormat | Экземплярный метод | Добавление форматированной строки в конец строки |
Capacity | свойство | Получение и установка емкости буфера. Если устанавливаемое значение меньше текущей длины строки или больше максимального, то генерируется исключение ArgumentOutOfRangeException |
Insert | Экземплярный метод | Вставка подстроки в заданную позицию |
Length | изменяемое свойство | Возвращает длину строки. Присвоение ему значения 0 сбрасывает содержимое и очищает строку |
MaxCapacity | неизменное свойство | Возвращает наибольшее количество символов, которое может быть размещено в строке |
Remove | Экземплярный метод | Удаление подстроки из заданной позиции |
Replace | Экземплярный метод | Замена всех вхождений заданной подстроки или символа новой подстрокой или символом |
ToString | Экземплярный метод | Преобразование в строку типа string |
Chars | изменяемое свойство | Возвращает из массива или устанавливает в массиве символ с заданным индексом. Вместо него можно пользоваться квадратными скобками [] |
Equals | Экземплярный метод | Возвращает true, только если объекты имеют одну и ту же длину и состоят из одних и тех же символов |
CopyTo | Экземплярный метод | Копирует подмножество символов строки в массив char |
Как видим, методы класса StringBuilder менее развиты, чем методы класса String, но они позволяют более эффективно использовать память за счет работы с изменяемыми строками. Рассмотрим примеры использования данных методов.
static void Main(){ try { StringBuilder str=new StringBuilder("Площадь"); PrintString(str); str.Append(" треугольника равна"); PrintString(str); str.AppendFormat(" {0:f2} см ", 123.456); PrintString(str); str.Insert(8, "данного "); PrintString(str); str.Remove(7, 21); PrintString(str); str.Replace("а", "о"); PrintString(str); StringBuilder str1=new StringBuilder(Console.ReadLine()); StringBuilder str2=new StringBuilder(Console.ReadLine()); Console.WriteLine(str1.Equals(str2)); } catch { Console.WriteLine("Вознико исключение"); }} static void PrintString(StringBuilder a){ Console.WriteLine("Строка: "+a); Console.WriteLine("Текущая длина строки " +a.Length); Console.WriteLine("Объем буфера "+a.Capacity); Console.WriteLine("Максимальный объем буфера "+a.MaxCapacity); Console.WriteLine();}Задание. Самостоятельно изучите метод CopyTo.
С изменяемой строкой можно работать не только как с объектом, но как с массивом символов:
static void Main(){ StringBuilder a = new StringBuilder("2*3=3*2"); Console.WriteLine(a); int k=0; for (int i = 0; i < a.Length; ++i ) if (char.IsDigit(a[i])) k+=int.Parse(a[i].ToString()); Console.WriteLine(k);}На практике часто комбинируют работу с изменяемыми и неизменяемыми строками. Однако если необходимо изменять строку, то в этом случае используют StringBuilder.
Пример. Дана строка, в которой содержится осмысленное текстовое сообщение. Слова сообщения разделяются пробелами и знаками препинания. Вывести все слова сообщения, которые начинаются и заканчиваются на одну и ту же букву.
static void Main(){ Console.WriteLine("Введите строку: "); StringBuilder a = new StringBuilder(Console.ReadLine()); Console.WriteLine("Исходная строка: "+a); for (int i=0; i<a.Length;) if (char.IsPunctuation(a[i])) a.Remove(i,1); else ++i; string str=a.ToString(); string []s=str.Split(' '); Console.WriteLine("Искомые слова: "); for (int i=0; i<s.Length; ++i) if (s[i][0]==s[i][s.Length-1]) Console.WriteLine(s[i]);}Задание. Измените программу так, чтобы она корректно работала и для случая, когда в исходной строке встречаются лишние пробелы.
Практикум
Замечание. При решении задач следует руководствоваться правилом: если в строке должны производится изменения, то лучше пользоваться классом StringBuilder; если необходимо разбивать строки на слова, то классом String. При решении некоторых задач, потребуется использовать оба класса.
- Разработать программу, которая для заданной строки s:
- вставляет символ x после каждого вхождения символа y;
Пример
using System;using System.Text; namespace ConsoleApplication{ class Class { static void Main() { Console.WriteLine("Введите строку: "); StringBuilder a = new StringBuilder(Console.ReadLine()); Console.WriteLine("Исходная строка: "+a); Console.WriteLine("Введите символ x: "); char x=char.Parse(Console.ReadLine()); Console.WriteLine("Введите символ y: "); char y=char.Parse(Console.ReadLine()); for (int i=0; i<a.Length; ++i) if (a[i]==x){a.Insert(i+1,y); ++i;} Console.WriteLine("Измененная строка: "+a); } }}- меняет местами первую букву со второй, третью с четвертой и т.д.
- определяет, какой из двух заданных символов встречается чаще в строке;
- подсчитывает общее число вхождений символов х и y;
- подсчитывает количество букв в строке;
- определяет, имеются ли в строке два соседствующих одинаковых символа;
- удаляет среднюю букву, если длина строки нечетная, и две средних, если длина строки четная;
- удваивает каждое вхождение заданного символа x;
- удаляет все символы х;
- удаляет все подстроки substr;
- заменяет все вхождения подстроки substr1 на подстроку substr2;
- подсчитывает сумму всех содержащихся в ней цифр;
- подсчитывает количество содержащихся в ней цифр;
- находит порядковые номера первого и последнего вхождения символа x;
- заменяет все группы стоящих рядом точек на многоточие;
- выводит на экран последовательность символов, расположенных до первого двоеточия;
- выводит на экран последовательность символов, расположенных после последнего двоеточия;
- удаляет из нее последовательность символов, расположенных между круглыми скобками (считается, что в строке ровно одна пара круглых скобок).
- удаляет из нее последовательность символов, расположенных между двумя запятыми (считается, что в строке ровно две запятые);
- определяет, сколько различных символов встречается в строке.
- Дана строка, в которой содержится осмысленное текстовое сообщение. Слова сообщения разделяются пробелами и знаками препинания.
- Вывести только те слова сообщения, в которых содержится заданная подстрока.
Пример
using System;using System.Text; namespace ConsoleApplication{ class Class { static void Main() { Console.WriteLine("Введите строку: "); StringBuilder a = new StringBuilder(Console.ReadLine()); Console.WriteLine("Исходная строка: "+a); Console.WriteLine("Введите заданную подстроку: "); string x=Console.ReadLine(); for (int i=0; i<a.Length;) if (char.IsPunctuation(a[i]))a.Remove(i,1); else ++i; string str=a.ToString(); str=str.Trim(); string []s=str.Split(' '); Console.WriteLine("Искомые слова: "); for (int i=0; i<s.Length; ++i) if (s[i].IndexOf(x)!=-1) Console.WriteLine(s[i]); } }}- Вывести только те слова сообщения, которые содержат не более чем n букв.
- Вывести только те слова сообщения, которые начинаются с прописной буквы.
- Вывести только те слова сообщения, которые содержат хотя бы одну цифру.
- Удалить из сообщения все слова, которые заканчиваются на заданный символ.
- Удалить из сообщения все слова, содержащие данный символ (без учета регистра).
- Удалить из сообщения все однобуквенные слова (вместе с лишними пробелами).
- Удалить из сообщения все повторяющиеся слова (без учета регистра).
- Подсчитать сколько раз заданное слово встречается в сообщении.
- Подсчитать сколько слов, состоящих только из прописных букв, содержится в сообщении.
- Найти самое длинное слово сообщения.
- Найти все самые длинные слова сообщения.
- Найти самое короткое слово сообщения.
- Найти все самые короткие слова сообщения.
- Вывести на экран все слова-палиндромы, содержащиеся в сообщении.
- По правилу расстановки знаков препинания перед каждым знаком препинания пробел отсутствует, а после него обязательно стоит пробел. Учитывая данное правило, проверьте текст на правильность расстановки знаков препинания и, если необходимо, внесите в текст изменения.
- Вывести только те слова, которые встречаются в тексте ровно один раз.
- Вывести только те слова, которые встречаются более n раз.
- Вывести слова сообщения в алфавитном порядке.
- Вывести слова сообщения в порядке возрастания их длин.
Дата добавления: 2017-03-29; просмотров: 1631;