8.1. Класс char
В 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);
} //TestChar
Три символьные переменные инициализированы константами, значения которых заданы тремя разными способами. Переменная ch объявляется в объектном стиле, используя new и вызов конструктора класса. Тип char, как и все типы C#, является классом. Этот класс наследует свойства и методы класса Object и имеет большое число собственных методов.
Явные или неявные преобразования между классами char и string отсутствуют, но, благодаря методу ToString, переменные типа char стандартным образом преобразуются в тип string. Как отмечалось выше, существуют неявные преобразования типа char в целочисленные типы, начиная с типа ushort. Обратные преобразования целочисленных типов в тип char также существуют, но они уже явные.
В результате работы процедуры TestChar строка s, полученная сцеплением трех символов, преобразованных в строки, имеет значение BZX, переменная ch равна A, а ее код - переменная code - 65.
Не раз отмечалось, что семантика присваивания справедлива при вызове методов и замене формальных аргументов на фактические. Приведем две процедуры, выполняющие взаимно-обратные операции - получение по коду символа и получение символа по его коду:
public int SayCode(char sym) {
return sym;
}//SayCode
public char SaySym(object code) {
return (char)((int)code);
}// SaySym
Как видите, в первой процедуре преобразование к целому типу выполняется неявно. Во второй - преобразование явное. Ради универсальности она слегка усложнена. Формальный параметр имеет тип Object, что позволяет передавать ей в качестве аргумента код, заданный любым целочисленным типом. Платой за это является необходимость выполнять два явных преобразования.
Класс Char, как и все классы в C#, наследует свойства и методы родительского класса Object. Но у него есть и собственные методы и свойства, и их немало. Сводка этих методов приведена в таблице 5.
Таблица 5. Статические методы и свойства класса Char
Метод
|
Описание
|
GetNumericValue
|
Возвращает численное значение символа, если он является цифрой, и (-1) в противном случае
|
GetUnicodeCategory
|
Все символы разделены на категории. Метод возвращает Unicode категорию символа. Ниже приведен пример
|
IsControl
|
Возвращает true, если символ является управляющим
|
IsDigit
|
Возвращает true, если символ является десятичной цифрой
|
IsLetter
|
Возвращает true, если символ является буквой
|
IsLetterOrDigit
|
Возвращает true, если символ является буквой или цифрой
|
IsLower
|
Возвращает true, если символ задан в нижнем регистре
|
IsNumber
|
Возвращает true, если символ является числом (десятичной или шестнадцатиричной цифрой)
|
IsPunctuation
|
Возвращает true, если символ является знаком препинания
|
IsSeparator
|
Возвращает true, если символ является разделителем
|
IsSurrogate
|
Некоторые символы Unicode с кодом в интервале [0x1000, 0x10FFF] представляются двумя 16-битными "суррогатными" символами. Метод возвращает true, если символ является суррогатным
|
IsUpper
|
Возвращает true, если символ задан в верхнем регистре
|
IsWhiteSpace
|
Возвращает true, если символ является "белым пробелом". К белым пробелам, помимо пробела, относятся и другие символы, например, символ конца строки и символ перевода каретки
|
Parse
|
Преобразует строку в символ. Естественно, строка должна состоять из одного символа, иначе возникнет ошибка
|
ToLower
|
Приводит символ к нижнему регистру
|
ToUpper
|
Приводит символ к верхнему регистру
|
MaxValue, MinValue
|
Свойства, возвращающие символы с максимальным и минимальным кодом. Возвращаемые символы не имеют видимого образа
|
Большинство статических методов перегружены. Они могут применяться как к отдельному символу, так и к строке, для которой указывается номер символа для применения метода. Основную группу составляют методы 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
Результаты консольного вывода, порожденного выполнением метода, изображены на рис. 26.

Рисунок 26. Вызовы статических методов класса char
Кроме статических методов, у класса 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);
ch1 = 'а';
ch2 = 'А';
dif = ch1.CompareTo(ch2);
Console.WriteLine("Расстояние между символами {0}, {1} = {2}", ch1, ch2, dif);
ch1 = 'Я';
ch2 = 'А';
dif = ch1.CompareTo(ch2);
Console.WriteLine("Расстояние между символами {0}, {1} = {2}", ch1, ch2, dif);
ch1 = 'A';
ch2 = 'A';
dif = ch1.CompareTo(ch2);
Console.WriteLine("Расстояние между символами {0}, {1} = {2}", ch1, ch2, dif);
ch1 = 'А';
ch2 = 'A';
dif = ch1.CompareTo(ch2);
Console.WriteLine("Расстояние между символами {0}, {1} = {2}", ch1, ch2, dif);
ch1 = 'Ё';
ch2 = 'А';
dif = ch1.CompareTo(ch2);
Console.WriteLine("Расстояние между символами {0}, {1} = {2}", ch1, ch2, dif);
} //TestCompareChars
Результаты сравнения изображены на рис. 27.

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