Лабораторная работа №2 «Обработка строк Tcl/Tk»
Строки являются основным типом данных в Tcl, поэтому не удивительно, что в этом языке для их обработки предусмотрено большое количеств команд. С обработкой строк непосредственно связаны операции сравнена с шаблонами, которые можно рассматривать как усложненные процедуры сравнения строк. Подобные средства имеются и в других языках сценариев.
Команда string. Команда string реализует набор операций со строками. Например, при ниже рассматривается фрагмент кода определяющий длину строки, содержащейся в переменной:
set name «Brent Welch»
string length $name
=> 11
Первый параметр команды string указывает, какая операция должна выполняться над строковым значением. Для того чтобы отобразить сведения о всех операциях, надо при вызове string задать недопустимый первый параметр:
string junk
=>bad option «junk»: should be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, tolower, totitle, toupper, trim, trimleft, trimright, wordend, or wordstart
Данный прем можно применять не только при работе с командой string. Задавая неверный параметр, можно получить сведения об использовании многих команд. Операции, реализуемые посредством команды string, описаны в таблице 2.1.
Таблица 2.1. Операции, реализуемые с помощью команды string
| string bytelength строка | Возвращает число байтов, необходимое для хранения строки. Это значение может отличаться от длины строки из-за особенностей формата UTF-8 |
| string compare ?-nocase? ?-length
число символов? строка_1 строка_2 |
Сравнивает строки по лексикографическому критерию. Опция -nocase задает сравнение без учета регистра символов. Опция -length ограничивает сравнение указанным числом символов. В случае равенства строк возвращается значение 0. Если первая строка лексикографически предшествует второй, возвращается значение -1, в противном случае — значение 1 |
| string equal ?-nocase?
строка_1 строка_2 |
Выполняет сравнение строк и возвращает значение 1, если они совпадают. Опция -nocase задает сравнение без учета регистра символов |
| string first подстрока строка?
начальный_индекс? |
Возвращает индекс первого вхождения подстроки в строку. Если подстрока не найдена, возвращается значение -1. Чтобы поиск осуществлялся не с начала строки, надо задать начальный индекс |
| string index строка индекс | Возвращает символ, находящийся в указанной позиции. Индекс отсчитывается начиная с нуля. Для указания последнего символа в строке используется индекс end |
| string is класс ?-strict? ?-failindex имя_переменной? строка | Если строка принадлежит классу, возвращается значение 1. Если задана опция -strict, пустая строка считается не принадлежащей классу, в противном случае пустая строка считается принадлежащей классу. Если задана опция -failindex, то указанной переменной присваивается индекс символа, который исключает принадлежность строки классу. |
| string last подстрока строка
?начальный.индекс? |
Возвращает индекс последнего вхождения подстроки в строку. Если подстрока не найдена, возвращается значение -1. Чтобы поиск осуществлялся с середины строки, надо задать начальный индекс |
| string length строка | Возвращает число символов в строке |
| string map ?-nocase? карта_ символов строка | Возвращает новую строку, сформированную путем преобразования по карте символов (карта символов будет обсуждаться далее в этой главе) |
| string match ?-nocase? шаблон строка | Возвращает значение 1, если строка соответствует шаблону; в противном случае возвращается 0. Сравнение производится способом, типичным для команды glob |
| string range строка первый_индекс
второй_индекс |
Возвращает символы, расположенные в строке от первого до второго индекса |
| string repeat строка счетчик | Возвращает строку, повторенную указанное число раз |
| string replace строка первый_индекс
второй_индекс ?новая_ строка? |
Возвращает новую строку, в которой символы от первого до второго индекса либо удалены, либо заменены новой строкой |
| string tolower строка ?первый_индекс ? ?второй_индекс? | Преобразует символы, содержащиеся в строке, в нижний регистр. Первый и второй индексы определяют диапазон, в котором должно выполняться преобразование |
| string totitle строка ?первый_индекс? ?второй_индекс? | Преобразует строку следующим образом. Первый символ преобразуется в верхний регистр или в регистр заголовка Unicode. Остальные символы преобразуются в нижний регистр. Первый и второй индексы задают диапазон, в котором осуществляется преобразование |
| string toupper строка ?первый_индекс? ?второй_индекс ? | Преобразует символы, содержащиеся в строке, в верхний регистр. Первый и второй индексы определяют диапазон, в котором должно выполняться преобразование |
| string trim строка ?символы? | Если указанные символы присутствуют в начале или в конце строки, они удаляются. По умолчанию удаляются пробелы |
| string trimleft строка ?символы? | Если указанные символы присутствуют в начале строки, они удаляются. По умолчанию удаляются пробелы |
| string trimright строка ?символы? | Если указанные символы присутствуют в конце строки, они удаляются. По умолчанию удаляются пробелы |
| string wordend строка ix | Возвращает индекс символа, следующего после слова, которое содержит символ с индексом ix |
| string wordstat строка ix | Возвращает индекс первого символа в слове, которое содержит символ с индексом ix |
Ниже перечислены наиболее часто используемые операции.
- Операция проверки совпадения строк — equal.
- Операция проверки соответствия — match.
- Операции преобразования регистров символов — tolower, totitl и toupper.
- Операции удаления лишних пробелов (а по необходимости и других символов) — trim, trimright и trimleft.
- Операция is. Эта операция проверяет тип строки.
- Операция map. Преобразует символы.
- Операции repeat и replace.
- Операция totitle. С помощью данной операции удобно преобразовывать регистр символов.
Индексы. Для выполнения некоторых операций со строками надо знать индексы символов, т.е. позиции в строке. В Tсl символы в строке нумеруются начиная с 0. Для указания последнего символа используется специальный индекс с именем end.
string range abcd 2 end
=> cd
При извлечении подстроки часто применяются операции first, last, wordstart, wordend, index и range.
Строки в составе выражений. Выражения, содержащие строки, могут использоваться в командах ехрг, if и while. Для сравнения строк часто применяются операторы eq, ne, ==, !=, < и >. Однако, чтобы это стало возможным, надо соблюдать ряд правил, в противном случае при выполнении команд будут возникать проблемы. В первую очередь необходимо помещать строковое выражение в кавычки, чтобы при разборе последовательность символов была идентифицирована как строка. Для группировки выражений следует использовать фигурные скобки, чтобы кавычки корректно обрабатывались интерпретатором.
if {$x == «foo»} команда
В команде expr сравнение строк корректно выполняется только при использовании оператора eq или пе. Несмотря на кавычки, операторы, которые могут быть применены как к строковым, так и к числовым значениям, стараются по возможности преобразовывать строки в число. Если впоследствии выясняется, что строка, преобразованная в число, должна участвовать в операции сравнения строк, выполняется обратное преобразование. При преобразовании в строку числовое значение всегда представляется в десятичном формате. Если строка выглядит как шестнадцатеричное или восьмеричное число, сравнение с другими строками может быть некорректным. Например, в результате выполнения следующего выражения возвращается значение true:
if {«Oxa-= «10»} { puts stdout ack! }
=> ack!
Для сравнения строк предпочтительнее использовать команды string, compare и string equal. В Tcl 8.4 были введены операции eq и nе ехрr. предназначенные для сравнения строк. Они обеспечивают высокую эффективность работы, так как при их использовании исключается ненужное преобразование. Подобно функции языка С strcmp, команда string compare возвращает 0, если строки совпадают, —1 — если первая строка лексикографически предшествует второй, и 1 — если первая строка лексикографически следует за второй.
Пример 2.1.
if {[string compare $sl $s2] = = 0} {
# Строки совпадают
}
Еще проще использовать команду string equal:
Пример 2.2.
if {[string equal $sl $s2]} {
# Строки совпадают
}
Оператор eq выполняет те же действия, но записывается более компактно. Помимо того, он предотвращает нежелательные преобразования формата. Кроме оператора eq, существует также противоположный ему оператор пе.
Пример 2.3.
if {$sl eq $s2> {
# Строки совпадают
}
Сравнение строк с шаблонами. Команда string match поддерживает сравнение с шаблоном, подобное тому, которое реализуется командой glob. Такое сравнение позволяет при работе в Unix и других операционных системах определять, соответствует ли имя файла шаблону, указанному в групповой операции. В таблице 2.2 показаны три синтаксические конструкции, используемые при сравнении с шаблонами.
Таблица 2.2. Специальные символы, используемые при выполнении операции string match
| * | Помечает произвольное число символов |
| ? | Помечает один символ |
| [символы] | Помечает один символ из указанного набора |
Любые другие символы в составе шаблона интерпретируются как литералы. В следующем примере указан шаблон, которому соответствуют все строки, начинающиеся с символа а:
Пример 2.4.
string match a* alpha
=> 1
Шаблон, которому соответствуют лишь строки, состоящие из двух символов, приведен ниже.
string match ?? XY
=> 1
Следующее выражение определяет строки, начинающиеся либо с символа а, либо с символа b:
string match {[ab]*} cello
=> 0
Будьте осторожны! Квадратные скобки имеют в языке Tсl специальное назначение, поэтому шаблон, в котором используются квадратные скобки, надо помещать в фигурные скобки, иначе выражение в квадратных скобках будет интерпретировано как вложенная команда. В качестве шаблона также можно использовать значение переменной:
set pat {[ab]*x}
string match $pat box
=> 1
Все символы в определенном диапазоне можно представить с помощью выражения [х-у]. Например, шаблону [a-z] соответствуют все буквы нижнего регистра, а выражение [0-9] определяет все цифры. В одном наборе может быть указано несколько диапазонов. В следующем выражении содержится шаблон, определяющий любую латинскую букву, цифру или знак подчеркивания:
string match {[a-zA-Z0-9_]} $char
Выражение в квадратных скобках определяет лишь один символ. Чтобы описать более сложный шаблон, например строку, содержащую один или несколько символов из набора, надо воспользоваться регулярными выражениями.
Если вам надо указать литеральное значение символа *, ? или одной из скобок, перед ними надо указать обратную косую черту:
string match {*\?} what?
=> 1
Шаблон, в котором используется обратная косая черта, должен быть помещен в фигурные скобки, в противном случае интерпретатор Тс1 выполнит подстановку. Если вы не хотите использовать скобки, вместо одной надо указать две обратные косые черты. Перед сравнением с шаблоном Tсl заменит две обратные косые черты одной.
string match *\\? what?
Классы символов. Команда string is позволяет выяснить, принадлежит ли строка определенному классу. Таким образом могут проверяться данные, введенные пользователем. Например, чтобы удостовериться в том, что введенное значение является числом, можно использовать следующую команду:
if {![string is integer -strict $input]} {
error «Invalid input. Please enter a number.»
}
Классы определяются как наборы символов Unicode, поэтому они более содержательны, чем диапазоны значений ASCII-кодов. Например, класс alpha включает символы национальных кодировок, не попадающие в диапазон [A-Za-z].
Таблица 2.3. Имена классов символов
| alnum | Любая буква или цифра |
| alpha | Любая буква |
| ascii | Любой символ, код которого может быть представлен семью битами (т.е. код символа должен быть меньше 128) |
| boolean | Логическое значение, поддерживаемое в Tel: 0, 1. true, false (регистр символов может быть любым) |
| control | Символ, код которого меньше 32, но отличный от символа NULL |
| digit | Любая цифра |
| double | Допустимое число с плавающей точкой |
| false | Допустимое логическое значение, обозначающее в языке Tel «ложь»: 0 или false (регистр символов может быть любым) |
| graph | Любые печатные символы за исключением пробела |
| integer | Допустимое целое число |
| lower | Строка, представленная символами нижнего регистра |
Команда append. Команда append в качестве первого параметра получает переменную и добавляет к ней значения остальных параметров. Если на момент вызова команды переменная отсутствует, она создается.
set foo z
append foo a b с
set foo
=> zabc
Команда append эффективно работает с длинными строками. Данная команда непосредственно модифицирует переменные, поэтому она может использовать особенности распределения памяти в Tcl. Команда append записывается следующим образом:
append х «дополнительные данные»
Данная команда выполняется быстрее, чем следующая:
set х «$х дополнительные данные»
Команда format. Команда format выполняет те же функции, что и команда printf в языке С. Она форматирует строку в соответствии со спецификацией формата.
format спецификация значение_1 значение_2 …
Параметр, с помощью которого задается спецификация, содержит литералы и ключевые слова. Литералы копируются в форматируемую строку, а ключевые слова управляют форматированием соответствующих параметров. Ключевое слово начинается с символа %, за которым следует любое (в том числе нулевое) число модификаторов, и завершается спецификатором преобразования. В спецификаторе может содержаться до шести следующих компонентов.
- Спецификатор позиции.
- Флаги.
- Ширина поля.
- Точность.
- Длина слова.
- Символ преобразования.
В качестве примеров ключевых слов можно привести следующие: %f — для чисел с плавающей точкой, %d — для целых чисел и %s — для строк. Если в состав литерала надо включить символ %, его надо повторить дважды. В примерах, приведенных в данном разделе, спецификация формата помещается в двойные кавычки. Это необходимо потому, что в составе строк, определяющих формат, содержатся пробелы. С другой стороны, в тех же строках находятся символы, формируемые с помощью обратной косой черты, что предполагает подстановку. Таким образом, альтернатива двойным кавычкам в данном случае отсутствует. В таблице 2.4 приведены символы преобразования.
Таблица 2.4. Символы, используемые для преобразования формата
| d | Целое число со знаком |
| u | Беззнаковое целое |
| i | Целое число со знаком. Параметром может быть шестнадцатеричный (Ох) или восьмеричный (0) формат |
| 0 | Беззнаковое восьмеричное число |
| x или X | Беззнаковое шестнадцатеричное число. Символ ‘х‘ указывает на то, что результат должен быть представлен в нижнем регистре |
| с | Отображение целого числа в соответствующий символ ASCII |
| s | Строка |
| f | Число с плавающей точкой в формате а.b |
| е или Е | Число с плавающей точкой в формате, принятом для научных исследований, т.е. а. bЕ+-с |
| g или G | Число с плавающей точкой. В качестве формата выбирается либо %f, либо %е, в зависимости от того, какой из них дает более короткое представление |
Спецификатор позиции записывается в формате i$. Это означает, что вместо соответствующего параметра должно использоваться значение параметpa i. Отсчет позиций начинается с единицы. Указав позицию для одного ключевого слова, надо указать позицию для всех слов. Если для группировки спецификации формата используются двойные кавычки, символ $ должен предваряться обратной косой чертой.
set lang 2
format «%${lang}\$s» one un uno
=> un
Спецификатор позиции удобно применять для выбора строки из набора, как это делается в приведенном выше примере. Данную задачу также можно решить с помощью каталога сообщений. Спецификатор позиции также применяется в том случае, если одно и то же значение должно несколько раз включаться в форматируемую строку.
Флаги используются для управления заполнением и выравниванием. В приведенном ниже примере флаг # указывает на то, что перед шестнадцатеричным значением должны выводиться символы Ох. Число 0 в последовательности 08 означает, что поле должно быть заполнено нулями.
format «%#х» 20
=> 0x14
format «%#08х» 10
=> ОхОООООООа
Назначение символов, используемых в качестве флагов, описано в таблице 2.5.
После флагов указывается минимальная длина поля. Если длина поля больше числа символов, лишние позиции поля заполняются пробелами. При наличии флага 0 в качестве заполнителя используется символ 0.
format «%-20s %.3d» Label 2
=> Label 2
Таблица 2.5. Флаги форматирования
| — | Выравнивание по левому краю поля |
| + | Всегда отображать знак (+ или —) |
| пробел | Всегда предварять число пробелом, даже если оно содержит знак. Это удобно при последовательном выводе набора значений |
| 0 | Заполнение нулями |
| # | Начинать восьмеричные цифры с нуля, а шестнадцатеричные — с последовательности Ох. В состав числа с плавающей запятой всегда включать десятичную точку. Не удалять ведущие нули (°/,g) |
Если вы хотите, чтобы ширина поля вычислялась в программе и передавалась команде format как параметр, то в качестве спецификатора ширины поля надо использовать символ *. В приведенном ниже примере первый параметр определяет длину поля, а команда format форматирует последующие параметры.
set maxl 8
format «%-*s = %» $maxl Key Value
=> Key =Value
Далее в ключевом слове определяется точность, которая задается посредством числа с десятичной точкой. Для %f и %е спецификатор точности задает, сколько цифр должно следовать за десятичной точкой. Для %g спецификатор указывает общее количество значащих цифр. Для %d и %х определяется, сколько цифр должно быть выведено (по мере необходимости лишние позиции заполняются нулями).
format «%6.2f %6.2d» 1 1
=> 1.00 01
Последним в ключевом слове указывается длина. Эта информация имеет смысл только в версии Tcl 8.4, в которой была реализована поддержка расширенных целых чисел. Значения с плавающей точкой Tcl интерпретирует как числа с двойной точностью, а целые — как длинные целые числа. Расширенные целые содержат как минимум 64 бита. Добавляя символ l (long) к спецификатору длины, можно продемонстрировать различие между обычными и расширенными целыми.
format % u -1
=> 4294967295
format %lи -1
=> 18446744073709551615
Команда scan. Команда scan выполняет разбор строки в соответствии с описанием формата и присваивает значения переменным. Она возвращает число успешно выполненных преобразований. Если ни одна переменная не указана, команда возвращает список, содержащий результаты сканирования. Для обращения к команде scan применяется следующее выражение:
scan строка формат ?’переменная? ?переменная? ?переменная? …
Описание формата для команды scan составляется практически так же, как и для команды format. Например, посредством формата %с код единичного символа преобразуется в десятичное представление.
С помощью описания формата команды scan можно задавать наборы символов. Для формирования набора используются квадратные скобки. В составе набора указывается один или несколько символов, которые должны быть скопированы в переменную. Диапазон символов задается через дефис. Ниже приведен пример команды scan, которая присваивает переменной символы нижнего регистра, находящиеся в составе исходной строки.
scan abcABC {%[a-z]} result
=> 1
set result
=> abc
Если первым символом набора является закрывающая квадратная скобка. она рассматривается как часть набора. Если набор начинается с символа ^, это означает, что формату строки соответствуют только символы, не принадлежащие указанному набору. Если в наборе должна присутствовать закрывающая квадратная скобка, ее надо поместить непосредственно после символа ^. Для того чтобы открывающая квадратная скобка оказалась частью набора, никаких специальных мер принимать не надо. Поскольку квадратные скобки являются специальными символами, вы, возможно, захотите использовать при указании формата фигурные скобки или указать перед квадратной скобкой обратную косую черту. Это вполне допустимо.
Индивидуальные задания
- Ввести строку, получить число байтов необходимое для её хранения. Если полученное значение меньше 10-ти то вычислить из полученного значения корень квадратный, если больше – рассчитать экспоненту от длины строки и вывести результат на экран.
- Ввести 2 строки. Сравнить их между собой без учета регистра. Если они равны сложить их длины, если нет – вычесть. Результат вывести на экран.
- Ввести 2 строки. Сравнить их между собой с учетом регистра. Если одна строка лексикографически предшествует другой вычислить квадрат суммы длин введенных строк, если нет – найди десятичный логарифм от длины каждой строки и вывести полученный результат.
- Ввести строку. Определить, какой символ находиться на 5 позиции в строке. Если это символ a то возвести длину строки в квадрат, если нет – возвести длину строки в куб. Полученный результат вывести на экран.
- Ввести 2 строки. Сравнить между собой их последние символы. Если они равны сложить длины строк, если нет – возвести сумму длин строк в квадрат.
- Ввести 3 строки. Если какая либо строка повторяется 2 раза, то преобразовать все символы в строках в прописные, иначе – в строчные.
- Ввести строку. Если указанные символы присутствуют в конце строки их удалить, определить длину получившейся строки и возвести её в пятую степень.
- Ввести 2 строки. Определить, какая из строк принадлежит к классу alpha. Сделать все символы этой строки прописными.
- Ввести 2 строки. Определить, какая из строк принадлежит к классу digit. Сделать все символы этой строки строчными.
- Ввести 2 строки. Определить, какая из строк принадлежит к классу graf. Определить длину этой строки и извлечь из нее квадратный корень.
- Ввести строку, определить ее длину. Добавить к ней строку произвольной длины, определить длину получившейся строки. Если длина полученной строки в 2 раза превышает длину изначальной строки, то сделать все буквы получившейся строки строчными, иначе – прописными.
- Ввести 3 строки. Вывести на экран те строки, длин которых меньше 3-х.
- Написать программу, показывающую возможности команды format.
- Написать программу, показывающую возможности команды scan.
- Ввести 2 строки. Определить, какая из строк начинается на символ, следующий в алфавите раньше другой. Вывести на экран строки в алфавитном порядке.
Контрольные вопросы
- Объяснить сходства и различия операций string compare и string equal.
- Назначение и работа команды format.
- Назначение и работа команды scan.
- Назначение и работа команды append.
- Классы символов. Применение, примеры.
- Сравнение строк с шаблонами. Применение, примеры.
- Строки в составе выражений. Правила применения.
- Индексы. Применение, примеры.
- Назначение и работа команды string.
- Флаги форматирование. Применение, примеры.
