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

C# для чайников

.pdf
Скачиваний:
183
Добавлен:
27.03.2015
Размер:
15.52 Mб
Скачать

К свойствам проекта можно обратиться, щелкнув правой кнопкой мыши

имени проекта в Solution Explorer.

4.Теперь выберите команду меню Build: Rebuild Solution для полной сбор проекта, независимо от того, требуется она или нет.

5.Просмотрите подкаталог bin\Debug проекта MixingFunctionsAndMet odsWithXMLTags (или другой подкаталог, который был указан вами д XML-документации).

В этом подкаталоге должен находиться файл с указанным вами в п. 2 имена в котором содержится описание всех функций, документированных посредством XML-дескрипторов.

198

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

Глава 9

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

В этой главе...

> Основные операции со строками

} Разбор считанной строки

> Форматирование выводимых строк

многих приложениях можно рассматривать тип s t r i n g как один из встроен­ ных типов-значений наподобие i n t или c h a r . К строкам применимы некото­ рые из операций, зарезервированных для встроенных типов, например:

int i =

1;

//

Объявление и

инициализация i n t

s t r i n g s

=

" a b c " ;

// Объявление

и инициализация s t r i n g

С другой стороны, как видно из приведенного далее фрагмента, строки можно рас­ сматривать как пользовательский класс:

s t r i n g

s i

= n e w S t r i n g ( ) ;

s t r i n g

s 2

= " a b e d " ;

int n L e n g t h O f S t r i n g = s 2 . L e n g t h ;

Так что же такое s t r i n g — тип-значение или класс? На самом деле S t r i n g — это класс, который в силу его широкой распространенности С# трактует специальным обра­ зом. Например, ключевое слово s t r i n g представляет собой синоним имени класса String, как видно из следующего фрагмента исходного текста:

String

s i

=

" a b e d " ;

/ /

Присваивание

строкового литерала

 

 

 

 

/ /

объекту класса S t r i n g

s t r i n g

s 2

=

s i ;

/ /

Присваивание

объекта класса S t r i n g

//строковой переменной

Вэтом примере переменная si объявлена как объект класса S t r i n g (обратите внима­ ние на прописную S в начале имени), в то время как s2 объявлена как просто s t r i n g (сострочной s в начале имени). Однако эти два присваивания демонстрируют, что s t r i n g

иS t r i n g — это одинаковые (или совместимые) типы.

Вдействительности то же самое справедливо и для других встроенных ти­

пов. Даже тип i n t имеет соответствующий класс I n t 3 2, d o u b l e — класс D o u b l e и т.д.; отличие в том, что s t r i n g и S t r i n g — это действительно одно и то же.

Имеется ряд операций над строками, без которых не обходится практически никакая программа на С#. Например, почти во всех программах используется оператор "сложения" строк, показанный в следующем примере:

s t r i n g s N a m e = " R a n d y " ;

C o n s o l e . W r i t e L i n e ( " Е г о и м я - " + s N a m e ) ; / / К о н к а т е н а ц и я

Этот специальный оператор обеспечивается классом S t r i n g . Однако класс String предоставляет и другие методы для работы со строками. Их полный список можно найти в разделе " S t r i n g c l a s s " предметного указателя справочной системы.

Объединение неразделимо!

Вам нужно запомнить одну до сих пор неизвестную вам вещь: после того как объект s t r i n g создан, изменить его нельзя. Несмотря на то что можно говорить о модифика-1 ции строки, в С# нет операции, модифицирующей реальный объект s t r i n g . Внешне создается впечатление, что масса операторов модифицируют объекты s t r i n g , с кото- рыми работают, но это не так — они всегда возвращают модифицированную строку как новый объект s t r i n g .

Например, операция " Е г о и м я - " + " R a n d y " не изменяет ни одну из объединяемых строк, а генерирует новую строку " Е г о и м я - R a n d y " . Одним из побочных эффектов такого поведения является то, что вы не должны беспокоиться, что кто-то изменит строку без вашего ведома.

Рассмотрим следующую демонстрационную программу:

/ / M o d i f y S t r i n g - м е т о д ы к л а с с а S t r i n g н е м о д и ф и ц и р у ю т с а м

/ / о б ъ е к т

( s . T o U p p e r O

н е и з м е н я е т с т р о к у s ; в м е с т о э т о г о о н

/ / в о з в р а щ а е т н о в у ю п р е о б р а з о в а н н у ю с т р о к у )

u s i n g

S y s t e m ;

 

 

n a m e s p a c e

M o d i f y S t r i n g

 

 

{

 

 

 

 

c l a s s

P r o g r a m

 

 

{

 

 

 

 

p u b l i c

s t a t i c v o i d

M a i n ( s t r i n g [ ]

a r g s )

{

 

 

 

 

/ / С о з д а н и е

S t u d e n t

s i

s l . s N a m e

=

/ / С о з д а е м

S t u d e n t

s 2

s 2 . s N a m e

=

о б ъ е к т а S t u d e n t = n e w S t u d e n t ( ) ;

" J e n n y " ;

н о в ы й о б ъ е к т с т е м ж е и м е н е м = n e w S t u d e n t ( ) ;

s i . s N a m e ;

/ /

" И з м е н е н и е " и м е н и о б ъ е к т а s i

/ /

о б ъ е к т , п о с к о л ь к у T o U p p e r O

н е и з м е н я е т с а м в о з в р а щ а е т н о в у ю

200

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

// строку,

не влияя на оригинал

 

s2.sName = s i . s N a m e . T o U p p e r ( ) ;

 

Console . WriteLine("si - { o } ,

s2 -

{ l } " ,

 

s1 . sName,

 

 

 

s 2 . s N a m e ) ;

 

 

// Ожидаем

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

Console . WriteLine("Нажмите <Enter>

для " +

 

"завершения

п р о г р а м м ы . . . " ) ;

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

 

 

}

II Student - простейший класс, содержащий строку class Student

{

public String sName;

}

}

Объекты класса Student si и s2 созданы так, что их члены sName указывают на од­ ни и те же строковые данные. Вызов метода ToUpper () преобразует строку si . sName, изменяя все ее символы на прописные. Никаких проблем, связанных с тем, что si и s2 указывают на один объект, не возникает, поскольку метод ToUpper () не изменяет sName, а создает новую строку, записанную прописными буквами.

Вот что выводит на экран приведенная выше программа:

Sl - Jenny, s2 - JENNY

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

Это свойство строк называется неизменностью (или неизменяемостью). Неизменность строк очень важна для строковых констант. Строка наподобие "Это строка" представляет собой вид строковой константы, как 1 представ­ ляет собой константу типа int. Компилятор, таким образом, может заменить все обращения к одинаковым константным строкам обращением к одной кон­ стантной строке, что снижает размер получающейся программы. Такое поведе­ ние компилятора было бы невозможным, если бы строки могли изменяться.

Сравнение строк

Множество операций рассматривает строку как единый объект— например, метод Compare ( ) , который сравнивает две строки, вводя для них отношение "меньше-больше".

Если левая строка больше правой, Compare () возвращает 1.

Если левая строка меньше правой, Compare () возвращает -1.

Если строки равны, Compare () возвращает 0.

Вот как выглядит алгоритм работы Compare ( ) , записанный с использованием псев­ докода:

compare (string sl, string s2)

{

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

//

Циклический

проход

по всем

символам строк, пока один из

//

символов одной строки не окажется больше

 

 

//

соответствующего ему

символа второй строки

 

 

f o r e a c h

(для

каждого)

символа

более короткой

строки

if

(числовое

значение символа строки sl > числового

 

 

значения

символа

 

строки

s2)

 

 

 

 

r e t u r n 1

 

 

 

 

 

 

 

if

 

(числовое значение символа строки sl < числового

 

 

значения

символа

 

строки

s2)

 

 

 

 

r e t u r n -1

 

 

 

 

 

 

//

Если

все

символы совпали,

но строка sl длиннее строки

//

s2,

то она

считается

больше строки s2

 

 

if В

строке

sl

остались

символы

 

 

r e t u r n

1

 

 

 

 

 

 

 

//

Если

все

символы совпали,

но строка s2 длиннее строки

//,

sl,

то она

считается больше строки sl

 

 

if

В

строке

s2

остались

символы

 

 

r e t u r n

- 1

 

 

 

 

 

 

 

//

Если все символы строк попарно одинаковы,

и

строки

//

имеют одну

и ту же

длину —

то это одинаковые

строки

r e t u r n О

}

Таким образом, "abed" больше "abbd", a "abede " больше "abed" . Как правило, в реальных ситуациях интересует не то, какая из строк больше, а равны ли две строки друг другу или нет

Сравнение строк "больше-меньше" необходимо для их сортировки.

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

Программа BuildASentence предлагает пользователю ввести несколько строк текста. Эти строки объединяются с предыдущими для построени единого предложения. Программа завершает работу, если пользователь вво­ дит слово EXIT, exit, QUI T или quit.

//BuildASentence - данная программа конструирует

//предложение путем конкатенации пользовательского ввода,

//до тех пор пока пользователь не введет команду

//завершения . Эта программа демонстрирует использование

//проверки равенства строк

using System;

namespace BuildASentence

{

public class Program

{

public static voi d Main(string[] args)

{

Console . WriteLine("Каждая введенная вами строка " "будет добавляться в предложение, "

202

Часть

III.

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

"пока вы не введете

EXIT or Q U I T " ) ;

// Запрашиваем пользовательский ввод

и соединяем

// вводимые пользователем фразы в единое целое, пока // не будет введена команда завершения работы

string sSentence = "" ; for( ; ; )

{

//

Получение очередной строки

Console . WriteLine("Введите с т р о к у " ) ;

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

// Выход при команде завершения

if

(IsTerminateString(sLine))

{

 

break;

}

// В противном случае добавление введенного к строке

sSentence = String . Concat(sSentence ,

s L i n e ) ;

// Обратная связь

 

Console . WriteLine("\пВы ввели: { о } " ,

s S e n t e n c e ) ;

}

Console .WriteLine("\пПолучилось:\n{OJ", s S e n t e n c e ) ; // Ожидаем подтверждения пользователя

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

Console.Read();

}

//IsTerminateString - возвращает true, если введенная

//строка представляет собой команду завершения работы

public static bool IsTerminateString(string source)

{

string[] sTerms = { "EXIT", "exit", "QUIT", "quit" };

//Сравниваем введенную строку с командами завершения

//работы

foreach (string sTerm in sTerms)

{

// Возвращаем true при совпадении

if (String.Compare(source, sTerm) == 0)

{

return true ;

} }

return false;

После краткого описания своих действий программа создает пустую строку для пред- ложения — sSentence, после чего входит в "бесконечный" цикл.

Конструкции while (true) и for (; ;) представляют собой бесконечные циклы, выход из которых осуществляется посредством операторов break (выход из цикла) или return (выход из программы). Эти два цикла эквива­ лентны, и оба встречаются в реальных программах. О циклах подробно расска­ зывается в главе 5, "Управление потоком выполнения".

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

203

Далее программа предлагает пользователю ввести строку текста, которую затем счи тывает с помощью метода ReadLine ( ) . После прочтения строки программа проверяя не является ли введенная строка командой завершения работы, пользуясь для этого функцией IsTerminateString ( ) . Эта функция возвращает true, если переданная строка — одна из команд завершения работы, и false в противном случае.

По соглашению имя функции, проверяющей некоторое свойство и возвра щающей значение true или false, начинается с Is, Has, Can или иного по добного слова. Само собой, это соглашение предназначено исключительно для людей, для облегчения понимания и удобочитаемости программы — С# без различно, какое имя используется для функции.

Если введенная строка не является командой завершения работы, она добавляете в конец предложения посредством функции String . Concat ( ) . Полученный результа тут же выводится на экран, чтобы пользователь мог видеть, что у него получается.

Метод IsTerminateString () определяет массив строк sTerms. Каждый член этого массива представляет собой один из вариантов команды завершения работы. Лю бая из перечисленных в массиве строк, будучи введенной пользователем, приводит к за вершению работы программы.

В массив включены как строка "EXIT", так и строка "exit", поскольку функ ция Compare () по умолчанию рассматривает эти строки как различные (так что другие варианты написания этого слова, такие как " exit " или " Exit ", не буду восприняты программой в качестве команд завершения).

Функция IsTerminateString () циклически просматривает все элементы массив команд завершения работы и сравнивает их с переданной строкой. Если функция Соm pare () сообщает о соответствии строки одному из образцов команд завершения, функ ция тут же возвращает значение true; если же до завершения цикла соответствие не

найдено, то по выходе из цикла функция возвращает значение fa 1 зе.

Итерации по массиву — отличный способ проверки на равенство одному из возможных значений.

Вот пример вывода программы BuildASentence .

Каждая введенная вами строка будет добавляться в предложение, пока вы не введете EXIT or QUI T Введите строку

П р о г р а м м и р о в а н ие на С#

Вы ввели: Программирование на С# Введите строку

-сплошное удовольствие

Вы ввели: Программирование на С# - сплошное удовольствие Введите строку

EXIT

П о л у ч и л о с ь :

204

Часть III.

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

Программирование на С# - сплошное удовольствие

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

Пользовательский ввод здесь выделен полужирным шрифтом.

Сравнение без учета регистра

Метод Compare ( ) , использованный в функции IsTerminateString ( ) , рассмат­ ривает строки "EXIT" и "exit" как различные. Однако имеется перегруженная версия функции Compare ( ) , которой передается три аргумента. Третий аргумент этой функции указывает, следует ли при сравнении игнорировать регистр букв (значение true) или нет (значение false). О перегрузке функций рассказывалось в главе 7, "Функции функций".

Следующая версия функции IsTerminateString () возвращает значение true, какими бы буквами не была введена команда завершения.

// IsTerminateString - возвращает значение true,

если

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

завершения

// программы

 

public static bool IsTerminateString (string source)

{

// Проверяет, равна ли переданная строка строкам exit

//или quit, независимо от регистра используемых букв return (String . Compare("exit", source, true) == 0)

(String . Compare("quit", source, true) = = 0 ) ;

)

Эта версия функции IsTerminateString () проще предыдущей версии с исполь­ зованием цикла. Ей не надо заботиться о регистре символов, и она может обойтись всего лишь двумя условными выражениями, так как ей достаточно рассмотреть только два ва­ рианта команды завершения программы.

Обратите внимание, что приведенная версия функции IsTerminateString () не применяет оператор if. Вычисленное значение логического выражения просто непосредственно передается пользователю, что позволяет избежать применения if.

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

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

//IsTerminateString - возвращает значение true,

если

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

завершения

// программы

 

public static bool IsTerminateString (string source)

{

switch (source)

{

case "EXIT" : case "exit" :

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

205

case "QUIT": case "quit":

return true ;

}

return false;

}

Такой подход работает постольку, поскольку выполняется сравнение только пред­ определенного ограниченного количества строк. Цикл for () представляет собой сущ ственно более гибкий подход, а применение функции Compare ( ) , нечувствительно! к регистру, существенно повышает возможности программы по "пониманию" введенно­ го пользователем.

Считывание ввода пользователя

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

Ваша программа может считывать строки, как если бы это были массива символов, с использованием оператора f oreac h или оператора индекса [], Приведенный ниже исходный текст программы StringToCharAccess демонстрирует данную методику.

// StringToCharAccess - обращение к

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

// если бы строка была массивом

 

using System;

 

namespace

StringToCharAccess

 

{

 

 

public class Program

 

{

 

 

public

static voi d Main(string[]

args)

{

 

 

//Считывание строки с клавиатуры

Console . WriteLine("Введите произвольную " + "строку с и м в о л о в . " ) ;

string sRandom = 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 ( ) ;

//Выводим стоку

Console . WriteLine("Вывод строки: " + s R a n d o m ) ;

C o n s o l e . W r i t e L i n e ( ) ;

// Выводим ее как последовательность символов Console . Write("Вывод с использованием foreach: " ) ; foreach(char с in sRandom)

{

C o n s o l e . W r i t e ( с ) ;

}

C o n s o l e . W r i t e L i n e ( ) ; .// Завершение строки

// Пустая строка - разделитель

206

Часть

III.

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

C o n s o l e . W r i t e L i n e ( ) ;

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

C o n s o l e . W r i t e ( " В ы в о д с и с п о л ь з о в а н и е м for: " ) ; for(int i = 0; i < sRandom . Length; i++)

{

C o n s o l e . W r i t e { s R a n d o m [ i ] ) ;

}

C o n s o l e . W r i t e L i n e ( ) ; / / З а в е р ш е н и е с т р о к и

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

C o n s o l e . W r i t e L i n e ( "Нажмит е <Enter> д л я " +

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

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

Эта программа выводит некоторую совершенно случайную строку, вводимую поль­ зователем. Сначала строка выводится обычным способом с применением метода WriteLine (string) . Затем для вывода строки используется цикл f oreach, который выводит ее символы по одному. И наконец, для той же цели применяется цикл for на­ ряду с оператором индекса [ ]. В результате на экране получается примерно следующее:

Введите

п р о и з в о л ь н у ю

с т р о к у

с и м в о л о в .

Вывод

с т р о к и : dj n dfv ckexfqyfz

cnhjrf

Вывод

с

и с п о л ь з о в а н и е м

foreach:

djn

dfv ckexfqyfz cnhjrf

Вывод

с

и с п о л ь з о в а н и е м

for:

dj n

dfv

ckexfqyfz cnhjrf

Нажмите

<Enter> д л я

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

Зачастую требуется убрать все пробельные символы с обоих концов строки (под тер­ мином пробельный символ (white space) подразумеваются символы, обычно не отобра­ жаемые на экране, например, пробел, символ новой строки или табуляции). Для этого можно воспользоваться методом Trim ():

// Удаляем п р о б е л ь н ы е с и м в о л ы с к о н ц о в с т р о к и sRandom = sRandom. Trim () ;

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

Разбор числового ввода

Функция ReadLine () используется для считывания объекта типа string. Про­ грамма, которая ожидает числовой ввод, должна эту строку соответствующим образом преобразовать в числа. С# предоставляет программисту класс Convert со всем необхо­ димым для этого инструментарием, в частности, методами для преобразования строки в каждый из встроенных числовых типов. Так, следующий фрагмент исходного текста считывает число с клавиатуры и сохраняет его в переменной типа int.

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

207

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]