Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Books / 3_C#_2005_для_чайников_(Дэвис-2008)

.pdf
Скачиваний:
86
Добавлен:
24.03.2015
Размер:
15.46 Mб
Скачать

той, функция возвращает false, указывая, что переданная ей строка не является чис­ том. Возврат функцией значения true означает, что все символы строки — цифры, так что строка, по всей видимости, представляет собой некоторое числовое значение.

Следующая демонстрационная программа считывает вводимое пользовате­ лем число и выводит его на экран:

// IsAllDigits - демонстрационная программа, иллюстрирующая [// применение функции IsAllDigits

using System;

namespace IsAllDigits

{

class

Program

 

 

 

 

 

{

 

 

 

 

 

 

 

public

static voi d Main(string[]

args)

{

 

 

 

 

 

 

 

// Ввод строки с клавиатуры

 

 

 

Console . WriteLine("Введите целое

ч и с л о " ) ;

string s =

C o n s o l e . R e a d L i n e ( ) ;

 

 

// Проверка, может ли эта строка

быть числом

if

(!IsAllDigits(s))

 

 

 

 

{

 

 

 

 

 

 

 

 

Console . WriteLine("Это

н е

ч и с л о ! " ) ;

}

 

 

 

 

 

 

 

else

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

// Преобразование строки в целое число

 

int

n =

I n t 3 2 . P a r s e ( s ) ;

 

 

 

 

//

Выводим число, умноженное

на 2

 

Console . WriteLine("2 *

{ о }

=

{ l } " , n, 2 * n ) ;

}

// Ожидаем подтверждения пользователя Console . WriteLine("Нажмите <Enter> для " +

"завершения п р о г р а м м ы . . . " ) ;

Console . Read();

}

// IsAllDigits - возвращает true, если все символы

//строки

//являются цифрами

public static bool IsAllDigits(string sRaw)

{

 

 

 

 

 

 

 

//

Тело

функции

было рассмотрено ранее

и здесь

оно

для

II

краткости

опущено

 

 

 

Программа считывает строку, вводимую пользователем с клавиатуры, после чего вы­ полняет ее проверку с помощью функции IsAllDigits. Если функция возвращает false, программа выводит пользователю предупреждающее сообщение. Если же нет,

Глава 9. Работа со строками в С #

209

программа преобразует строку в число с помощью функции Int3 2 . Parse ( ) , кош представляет собой альтернативу Convert . ToInt32 ( ) . И наконец, программа выво дит полученное число и его удвоенное значение (что должно доказывать корректность преобразования строки в число).

Вот как выглядит пример вывода рассматриваемой программы: В в е д и т е ц е л о е ч и с л о

1АЗ

Э т о н е ч и с л о !

Н а ж м и т е <Enter> д л я з а в е р ш е н и я п р о г р а м м ы . . .

Можно просто попытаться использовать функцию класса Convert для вьш нения преобразования строки в число, и обработать возможные исключен генерируемые функцией преобразования. Однако имеется немалая вероятна что при этом функция не сгенерирует исключения, а вернет некорректный зультат — например, в приведенном выше примере с вводом в качестве чи 1АЗ вернет значение 1.

Обработка последовательности чисел

Зачастую программы получают в качестве вводимых данных строку, состоящую нескольких чисел. Воспользовавшись методом String . Split ( ) , вы сможете лен разбить строку на несколько подстрок, по одной для каждого числа, и работать с ним| отдельности.

Функция Split () преобразует единую строку в массив строк меньшего рази

с применением указанного символа-разделителя. Например, если вы скажете функвД Split ( ) , что следует использовать в качестве разделителя запятую, строка "1,2, превратится в три строки — " 1", " 2" и " 3".

Приведенная далее демонстрационная программа применяет метод Split] для ввода последовательности чисел для суммирования.

/ / ParseSequenceWithSplit - с ч и т ы в а е т п о с л е д о в а т е л ь н о с т ь / / р а з д е л е н н ы х з а п я т ы м и ч и с е л , р а з д е л я е т е е н а о т д е л ь н ы е / / ц е л ы е ч и с л а и с у м м и р у е т и х

namespace ParseSequenceWithSplit

{

usin g System;

class Program

{

public static void Main(strin g [] args)

{

/ / П р и г л а ш е н и е п о л ь з о в а т е л ю в в е с т и п о с л е д о в а т е л ь н о с т ь / / ц е л ы х ч и с е л

C o n s o l e . W r i t e L i n e ( " В в е д и т е п о с л е д о в а т е л ь н о с т ь ц е л ы х " + " ч и с е л , р а з д е л е н н ы х з а п я т ы м и : " ) ;

/ / С ч и т ы в а н и е с т р о к и т е к с т а string input = C o n s o l e . R e a d L i n e О ; C o n s o l e . W r i t e L i n e ( ) ;

210

Часть III.

Объектно-основанное программирован*

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

//использованием в качестве символов - разделителей

//запятых и пробелов

char [] cDividers

= {',', 1 1} ;

string[]

segments

= i n p u t . S p l i t ( c D i v i d e r s ) ;

// Конвертируем каждую подстроку в число

int nSum

= 0;

 

foreach(string s

in segments)

{

//(Пропускаем пустые подстроки)

if (s.Length > 0)

{

//

Пропускаем строки, не являющиеся числами

if

(IsAllDigits(s))

{

//Преобразуем строку в 32 - битовое целое число

int n u m = I n t 3 2 . P a r s e ( s ) ;

Console . WriteLine("Очередно е число = { о } " , n u m ) ;

// Добавляем полученное число в сумму nSum += num;

}

// Вывод суммы

Console . WriteLine("Сумма = { о } " , n S u m ) ;

// Ожидаем подтверждения пользователя Console . WriteLine("Нажмите <Enter> для " +

"завершения программы .. . ") ;

C o n s o l e . R e a d ( ) ;

//

IsAllDigits - возвращает true, если

все символы

строки

//

являются цифрами

 

 

public static bool IsAllDigits(string sRaw)

 

{

 

 

 

 

//

Убираем все лишнее с концов строки . Если при этом в

//

строке ничего не остается - значит, эта строка не

//

представляет собой число

 

 

string s = s R a w . T r i m f ) ; // Игнорируем

пробельные

символы

if

(s.Length == 0)

 

 

{

return false;

}

// Циклически проходим по всем символам строки for (int index = 0; index < s.Length; index++)

{

//

Наличие

в строке символа,

не являющегося цифрой,

//

говорит

о том, что это не число

if

(Char.IsDigit(s[index]) ==

false)

{

 

 

 

return false;

tea 9. Работа со строками в С#

211

}

// Все в порядке : строка состоит только из цифр return true ;

}

}

Программа ParseSequenceWithSplit начинает со считывания строки с клав] ры. Затем методу Split () передается массив символов cDividers, представляю: собой символы-разделители, использующиеся при отделении отдельных чисел в строке.

Далее программа циклически проходит по всем "подмассивам", созданным фук Split ( ) , применяя для этой цели цикл foreach. Программа пропускает все подстрЯ нулевой длины, а для непустых строк вызывает функцию IsAllDigits () для тя чтобы убедиться, что строка представляет собой число. Корректные строки преобри ются в целые числа и суммируются с аккумулятором nSum. Некорректные числа щ рируются (я предпочел не генерировать сообщения об ошибках).

Вот как выглядит типичный вывод данной программы:

Введите

последовательность целых чисел, разделенных запятыми:

1, 2, а,

3, 4

Очередное число = 1 Очередное число = 2 Очередное число = 3 Очередное число = 4 Сумма = 10

Нажмите <Enter> для завершения программы ...

Программа проходит по списку, рассматривая запятые, пробелы (или оба симвсЯ вместе) как разделительные. Она пропускает "число" а и выводит общую сумму ц ректных чисел, равную 10. В реальных программах, однако, вряд ли можно простои игнорировать некорректные числа, никак не сообщая об этом пользователю. При not лении во входном потоке любой программы "мусора" обычно требуется тем или щ. способом привлечь к этому факту внимание пользователя.

Управление выводом программы представляет собой важный аспект работы со ста ками. Подумайте сами: вывод программы— это именно то, что видит пользователь. • имеет значения, насколько элегантна внутренняя логика и реализация программы —Ж вряд ли впечатлит пользователя; куда важнее для него корректность и внешнее предстш ление выводимых программой данных.

Класс String предоставляет программисту ряд методов для форматирования вьй димой строки. В следующих разделах будут рассмотрены такие методы, как Trim P a d ( ) , P a d R i g h t ( ) , P a d L e f t ( ) , S u b s t r i n g ( ) и C o n c a t ( ) .

Использование методов Trim() и Pad()

Методом Trim () можно воспользоваться для.удаления ненужных пробельных сю! волов с обоих концов строки. Обычно этот метод применяется для удаления оробело) при выравнивании выводимой строки.

212

Часть III.

Объектно-основанное программирован*

Еще один распространенный метод, часто используемый при форматировании — функции Pad, которые добавляют к строке пробелы с тем, чтобы ее длина стала равной некоторому предопределенному значению. Например, так вы можете добавить к строке пробелы слева или справа, чтобы обеспечить выравнивание вывода по правому или ле­ вому краю.

В приведенной далее небольшой демонстрационной программе AlignOut - put для выравнивания списка имен применяются обе упомянутые функции.

//AlignOutput - выравнивание множества строк для улучшения

//внешнего вида вывода программы

namespace AlignOutput

(

using System;

class Program

{

public static voi d Main(strin g [] args)

{

string[] names = {"Christa ",

"Sarah",

"Jonathan",

"Sam",

"Schmekowitz " } ;

//Вывод имен в том виде, в котором они получены Console.WriteLine("Имена имеют разную д л и н у " ) ;

foreach(string s in names)

{

Console.WriteLine("Имя '{о}' до обработки", s);

}

Console.WriteLine () ;

 

 

II

Выравниваем строки по левому краю и делаем их

 

//

равной

длины

 

 

string []

sAlignedNames = TrimAndPad(names) ;

 

// Выводим окончательный результат на экран

 

Console.WriteLine("Те же имена

выровнены и имеют

" +

 

 

"одинаковую

д л и н у " ) ;

 

foreach(string s in sAlignedNames)

 

Console.WriteLine("Имя ' {0} ' после обработки",

s) ;

}

II Ожидаем подтверждения пользователя

Console.WriteLine("Нажмите <Enter> для " + "завершения программы . . . " ) . ;

Console.Read();

 

}

 

Глава 9. Работа со строками в С#

213

//

TrimAndPad

- для данного массива строк удаляются

//

пробелы с

обоих сторон строки, после чего

выполняется

//

дополнение

пробелов таким образом, чтобы

все строки

//оказались выровнены с наибольшей строкой в массиве

public static string[] TrimAndPad(strin g [] strings)

{

//

Копируем исходный массив в

массив , с которым будем

//

работать

 

string[] stringsToAlign = ne w

S t r i n g [ s t r i n g s . L e n g t h ] ;

//

Удаляем ненужные пробелы с обоих сторон каждой

//

строки

 

for(int i = 0; i <

stringsToAlign . Length; i++)

{

 

stringsToAlign[i]

= s t r i n g s [ i ] . T r i m ( ) ;

}

 

// Находим наибольшую длину строки в массиве int nMaxLengt h = 0;

foreach(string

s

in stringsToAlign)

{

 

 

if (s.Length

>

nMaxLength)

{

 

 

nMaxLengt h

=

s.Length;

}

}

//Выравниваем все строки к длине самой длинной

for(int i = 0; i <

stringsToAlign . Length; i++)

{

 

stringsToAlign[i]

=

stringsToAlign[i] . PadRight(nMaxLengt h + 1 ) ;

}

// Возвращаем результа т вызывающей функции retur n stringsToAlign ;

}

}

}

Демонстрационная программа AlignOutput определяет массив имен, которые шеи разные выравнивание и длину (вы можете переписать программу так, чтобы эти имена счип вались с клавиатуры или из файла). Функция Main () сначала выводит эти имена на экран том виде, в котором они получены программой. Затем вызывается функция TrimAndPad существенно улучшающая внешний вид выводимых программой строк:

Имена

имеют разную

длину

Имя

'Christa

'

до

обработки

Имя

'

Sarah'

до

обработки

Имя

'Jonathan'

до обработки

Имя

'Sam' до обработки

Имя

'

Schmekowitz 1

до обработки

214

Часть

III.

Объектно-основанное программировя

Тe же имена

выровнены и имеют одинаковую длину

имя

'Christa

'

после

обработки

Вия

'Sarah

'

после

обработки

ta 'Jonathan

'

после

обработки

Имя

'Sam

'

после

обработки

Имя 'Schmekowitz ' после обработки

Нажмите <Enter> для завершения программы ...

Метод TrimAndPad () начинает с создания копии переданного ему массива strings. В общем случае функция, работающая с переданными ей аргументами, долж­ на вернуть новые модифицированные значения, а не изменять переданные ей.

TrimAndPad () начинается с цикла, вызывающего Trim () для каждого элемента массива, чтобы удалить лишние пробельные символы с обоих концов строки. Затем вы­ полняется второй цикл, в котором происходит поиск самого длинного элемента массива. И наконец, в последнем цикле для элементов массива вызывается метод PadRight (), удлиняющий строки, делая их равными по длине.

Метод PadRight (10) увеличивает строку так, чтобы ее длина была как минимум 10 символов. Например, если длина исходной строки — 6 символов, то метод PadRight (10) добавит к ней справа еще 4 пробела.

Метод TrimAndPad () возвращает массив выровненных строк для вывода. Функция lain () проходит по полученному списку строк, выводя их на экран. Вот и все.

Использование функции конкатенации

Зачастую программисты сталкиваются с задачей разбивки строки или вставки некоторой подстроки в середину другой строки. Заменить один символ другим проще всего (помощью метода Replace ():

string s = "Danger N o S m o k i n g " ; а.Replace (s, ' ' , ' ! ' )

Этот фрагмент исходного текста преобразует начальную строку в "Danger!NoSmoking". Замена всех вхождений одного символа (в данном случае — пробела) другим

(восклицательным знаком) особенно полезна при генерации списка элементов, разделен­ ии запятыми для упрощения разбора. Однако более распространенный и сложный слу­ чай включает разбиение единой строки на подстроки, отдельную работу с каждой под­ строкой с последующим объединением их в единую модифицированную строку.

Рассмотрим, например, функцию RemoveSpecialChar s ( ) , которая уда­ ляет все встречающиеся специальные символы из передаваемой ей строки. Демонстрационная программа RemoveWithSpac e использует функцию RemoveSpecialChars () для удаления из строки пробельных символов (пробелов, табуляций и символов новой строки).

//

RemoveWhiteSpace

-

определение

функции

 

//

RemoveSpecialChars

() ,

которая

может удалять

из

 

//передаваемой ей

строки произвольный предопределенный

 

// набор символов . В данной демонстрационной

программе

//

функция используется

для удаления из тестовой строки всех

//

пробельных

символов

 

 

 

namespace RemoveWhiteSpace

 

 

'та 9. Работа со строками в С#

215

*

u s i ng System;

public class Program

{

public static v o i d Main(string[] args)

{

//Определение множества пробельных символов

chart] cWhiteSpace = {' ', '\n', ' \ t ' } ;

// Начинаем работу со строкой, в которой имеются

//пробельные символы

string s = " this is a\nstring"; C o n s o l e . W r i t e L i n e ( " Д о : " + s ) ;

// Выводим строку с удаленными пробельными символами Console . WriteLine("После : " +

R e m o v e S p e c i a l C h a r s ( s , cWhiteSpace))

// Ожидаем подтверждения пользователя Console . WriteLine("Нажмите <Enter> для " +

"завершения программы .. . ") ;

C o n s o l e . R e a d ( ) ;

}

// R e m o v e S p e c i a l C h a r s - удаляет из строки все указанные

//символы

public static string R e m o v e S p e c i a l C h a r s ( s t r i n g slnput, chart] cTargets)

{

//В sOutput будет содержаться возвращаемая строка string sOutput = slnput;

//Начинаем поиск пробельных символов

for(;;)

{

// Ищем позиции искомых символов ; если таковых в

//строке больше нет — выходим из цикла

int

nOffset =

s O u t p u t . I n d e x O f A n y ( c T a r g e t s ) ;

if

(nOffset

-1)

{

break ;

}

// Разбиваем строку на две части — до найденного

//символа и после него

string

sBefore

=

sOutput . Substring(0 , n O f f s e t ) ;

string

sAfter

=

sOutput . Substring(nOffset + 1 ) ;

// и объединяем эти части, но уже без найденного

//символа

sOutput = String . Concat(sBefore , s A f t e r ) ;

216

Часть III. Объектно-основанное программировав

Глав

 

I

 

return sOutput;

Ключевой в этой демонстрационной программе является функция RemoveSpecial ­ Chars ( ) . Она возвращает строку, которая представляет собой исходную строку, но с удаленными вхождениями всех символов, содержащихся в массиве cTargets. Чтобы лучше понять эту функцию, представьте, что ей передана строка " ab, cd, е", а массив специальных символов содержит единственный символ ' , 1.

Функция RemoveSpecialChars () начинается с входа в цикл, выход из которого произойдет только тогда, когда в строке не останется ни одной запятой. Функция 1п- dexOf Any () возвращает позицию первой найденной запятой (значение -1 указывает, то ни одна запятая не найдена).

После первого вызова IndexOf An y () возвращает 2 (позиция 1 а1 равна 0, позиция b1 1, а позиция ' , ' — 2). Два следующих вызова функции разбивают строку на две подстроки в указанном месте. Вызов Substring (0, 2) создает подстроку, содержа­ щую два символа, начиная с символа в позиции 0, т.е. "ab". Второй вызов Substring (3) создает подстроку из символов с позиции 3 исходной строки и до ее юнца, т.е. "cd,e" (+1 в вызове позволяет пропустить найденную запятую). Затем функция Concat () объединяет эти подстроки вместе, создавая строку " abed, е".

Управление выполнением передается после этого в начало цикла. Очередная итераднл находит запятую в позиции 4, так что в результате получается строка " abede " . По­ скольку в ней нет ни одной запятой, возвращаемая при последнем проходе позиция рав- иа-1.

Демонстрационная программа сначала выводит строку, содержащую пробельные сиволы, затем использует функцию RemoveSpecialChar s () для их удаления и вы­ водит получившуюся в результате строку:

|о: this is а Wring

После :thisisastring

Зажмите <Enter> для завершения программы ...

Использование ф у н к ц и и SplitQ

В программе RemoveWhiteSpac e было продемонстрировано применение методов Concat () и IndexOf ( ) ; однако использованный способ решения поставленной задачи не самый эффективный. Стоит только немного поду­ мать, и можно получить существенно более эффективную функцию с ис­ пользованием уже знакомой функции Split О. Соответствующая про­ грамма имеется на прилагаемом компакт-диске в каталоге Remove - WhiteSpaceWithSplit. Вот код функции RemoveSpecialChar s () из этой программы.

//RemoveSpecialChars - удаляет из строки все указанные

//символы

rablic static string RemoveSpecialChar s (string slnput, char[] cTargets)

ирование

toa ft Работа со строками в С#

217

//Разбиваем входную строку с использованием указанных

//символов в качестве разделителей

string[] sSubStrings = s l n p u t . S p l i t ( c T a r g e t s ) ;

//В sOutput будет содержаться возвращаемая строка string sOutput = "";

//Цикл по всем подстрокам

foreach(string substring in sSubStrings)

{

sOutput = String . Concat(sOutput , s u b s t r i n g ) ;

}

return sOutput;

}

В этой версии для разбиения входной строки на множество подстрок использу функция Split () с удаляемыми символами в качестве символов-разделителей, скольку разделители не включаются в подстроки, создается эффект их удаления, логика гораздо проще и менее подвержена ошибкам при реализации.

Цикл f oreach в этой версии функции собирает части строки в единое целое. В программы остается неизменным.

Класс String предоставляет в распоряжение программиста метод Format О] форматирования вывода, в основном — чисел. В своей простейшей форме Forma позволяет вставлять строки, числа, логические значения в середину форматируа строки. Рассмотрим, например, следующий вызов:

string myString =

String . Format("{0} умножить на {l} равно { 2 } " , 2, 3, 2*3);

Первый аргумент Format () — форматная строка (строка формата). Элементы в ней указывают, что и-ый аргумент, следующий за форматной строкой, должен вставлен в этой точке. {0} означает первый аргумент (в данном случае — 2), {1 второй (3) и так далее.

Вприведенном фрагменте получившаяся строка присваивается переменной myStr

иимеет следующий вид:

2 умножить на 3 равно 6

Пока не указано иное, функция Format () использует формат по умолчанию для каж типа аргумента. Для указания формата вывода можно размещать в фигурных скобках к номера аргумента дополнительные модификаторы, которые показаны в табл. 9.1.

218

Часть III.

Объектно-основанное программирови