10.3. Функции для работы со строками
Глава 10 Работа со строками
🕛 02.11.2006, 15:59
В данном разделе мы рассмотрим некоторые встроенные функции языка Perl, предназначенные для работы со строками текста. Часть из них использует рассмотренное выше понятие регулярного выражения.ФуНКЦИЯ chop () chop
удаляет последний символ из всех элементов списка list, возвращает последний удаленный символ. Список может состоять из одной строки. Если аргумент отсутствует, операция удаления последнего символа применяется к встроенной переменной $_. Обычно применяется для удаления завершающего символа перевода строки, остающегося при считывании строки из входного файла.
ФуНКЦИЯ length() length EXPR
возвращает длину скалярной величины EXPR в байтах.
#!/usr/bin/perl \^_,.
$input = <STDIN>;
$Len = length($input);
print "Строка до удаления последнего символа: $input\n";
print "Длина строки до удаления последнего символа: $Len\n";
$Chopped = chop($input};
$Len = length($input);
print "Строка после удаления последнего символа: $input\n";
print "Длина строки после удаления последнего символа: $Len\n";
print "Удаленный символ: <$Chopped>\n";
Если после запуска данного скрипта ввести строку "qwerty", то вывод будет иметь вид:
qwerty
Строка до удаления последнего символа: qwerty
Длина строки до удаления последнего символа: 7 Строка после удаления последнего символа: qwerty Длина строки после удаления последнего символа: 6 Удаленный символ: < >
Последним символом, удаленным функцией chop (), является символ новой строки, сохраненный в переменной $chopped. При выводе он вызывает переход на следующую строку, поэтому в данном выводе третья строка - пустая. В последней операции print вывод осуществляется в две строки, так как переменная $chopped содержит символ новой строки.
Функции lc(), uc(), Icfirstf), ucfirstO
предназначены для преобразования строчных букв в прописные и наоборот.
ФуНКЦИЯ 1с EXPR
возвращает выражение, полученное из выражения EXPR преобразованием всех символов в строчные.
ФуНКЦИЯ UC EXPR
возвращает выражение, полученное из выражения EXPR преобразованием всех символов в прописные.
ФуНКЦИЯ Icfirst EXPR
возвращает выражение, полученное из выражения EXPR преобразованием первого символа в строчный.
ФуНКЦИИЯ ucf irst EXPR
возвращает выражение, полученное из выражения EXPR преобразованием первого символа в прописной.
#!/usr/bin/perl
print "\пФ-ция uc() преобразует ",$s="upper case"," в ",uc $s;
print "\пФ-ция ucfirst() преобразует ",$s="uPPER CASE"," в ",ucfirst $s;
print "\пФ-ция 1с() преобразует ", $s="LOWER CASE"," в ",1с $s;
print "\пф-ция IcfirstO преобразует ",$s="Lower case"," в ",lcfirst $s;
В результате выполнения данного скрипта будут напечатаны строки:
Ф-ция ис() преобразует upper case в UPPER CASE Ф-ция ucfirst() преобразует UPPER CASE в UPPER CASE Ф-ция 1с() преобразует LOWER CASE в lower case Ф-ция IcfirstO преобразует Lower case в lower case
ФуНКЦИЯ joint) join EXPR, LIST
объединяет отдельные строки списка LIST в одну, используя в качестве разделителя строк значение выражения EXPR, и возвращает эту строку.
Функция split ()
split [/PATTERN/[, EXPR[, LIMIT]]]
разбивает строку EXPR на отдельные строки, используя в качестве разделителя образец, задаваемый регулярным выражением PATTERN. В списковом контексте возвращает массив полученных строк, в скалярном контексте - их число. Если функция split о вызывается в скалярном контексте, выделяемые строки помещаются в предопределенный массив @_. Об этом не следует забывать, так как массив §_ обычно используется для передачи параметров в подпрограмму, и обращение к функции split о неявно в скалярном контексте эти параметры уничтожит.
Если присутствует параметр LIMIT, то он задает максимальное количество строк, на которое может быть разбита исходная строка. Отрицательное значение параметра LIMIT трактуется как произвольно большое положительное число.
Если параметр EXPR опущен, разбивается строка $_. Если отсутствует также и параметр PATTERN, то в качестве разделителей полей используются пробельные символы после пропуска всех начальных пробельных символов (что
соответствует заданию образца в виде /\s+/). К пробельным символам относятся пробел (space), символ табуляции ЛаЬ), возврат каретки (carriage feturn), символ перевода строки (line feed) и^симврл перевода страницы (form feed). .
Замечание Предопределенная глобальная переменная $_ служит для обозначения используемой по умолчанию области ввода и поиска по образцу. Обычно мы осуществляем ввод при помощи операции "о" ("ромб"). Внутри угловых скобок о может стоять дескриптор файла ввода, например, <STDIN>. Если дескриптор файла отсутствует, то в качестве файлов ввода используются файлы, переданные программе Perl в качестве аргументов командной строки. Пусть, например, программа содержится в файле script. pi.
#!/usr/bin/perl while (<>) {
print; };
Программа вызвана следующим образом script.pl filel file2 file3
Тогда операция о будет считывать строки сначала из файла filel, затем из файла file2 и, наконец, из файла file3. Если в командной строке файлы не указаны, то в качестве файла ввода будет использован стандартный ввод.
Только в случае, когда условное выражение оператора while состоит из единственной операции "ромб", вводимое значение автоматически присваивается предопределенной переменной $_. Вот что означают слова о том, что переменная $_ применяется для обозначения используемой по умолчанию области ввода. Аналогично обстоит дело с поиском по образцу.
I!/usr/bin/perl while (<>} {
chop;
print "Число полей во входной строке '$_' равно ", $n=split;
print "ХпВходная строка разбита на строки:\п";
foreach $i (@_) {
print $i . "\n"; }
print "Объединение списка строк в одну строку через ' +':\п";
$joined = join "+", @_;
print "$joined\n"; }
В результате применения операции ввода О внутри условного выражения оператора while вводимая строка будет присвоена переменной $_. Функция chop о без параметров применяется к переменной $_. В операции print вторым операндом является выражение $n=spiit, в котором функция split вызывается в скалярном контексте и без параметров. Поэтому она применяется по умолчанию к переменной $_. В качестве разделителей полей по умолчанию используется множество пробельных символов, а результат помещается в масссив @_. Затем к массиву @_ применяется функция joint), объединяющая строки-элементы массива в одну строку.
Если ввести строку "one two three", то вывод будет иметь вид:
one two three
Число полей во входной строке 'one two three' равно 3
Входная строка разбита на строки:
one
two
three
Объединение списка строк в одну строку через '+':
one+two+three
ФУНКЦИЯ index()
index STR, SUBSTR[, POSITION]
находит первое, начиная с позиции POSITION, вхождение подстроки SUBSTR в строку STR, и возвращает найденную позицию. Если параметр POSITION не задан, по умолчанию принимается значение POSITION = $[. Если подстрока SUBSTR не найдена, возвращается значение $ [ - 1.
Замечание Предопределенная переменная $ [ содержит индекс первого элемента в массиве и первого элемента в строке. По умолчанию ее значение равно 0. В принципе его можно изменить, но делать это не рекомендуется. Таким образом, по умолчанию значение параметра POSITION полагается равным 0, а функция index возвращает-1, если не найдена подстрока SUBSTR.
ФУНКЦИЯ rindex{)
rindex STR, SUBSTR, POSITION
находит последнее, ограниченное справа позицией POSITION, вхождение подстроки SUBSTR в строку STR, и возвращает найденную позицию. Если подстрока SUBSTR не найдена, возвращается значение $ [ - i.
f!/bin/peri - ,
$STR = "Этот безумный, безумный, безумный, безумный мир!";
$ SUBSTR = "безумный"; ^~-''
$POS = 7;
print "Индекс первого символа строки по умолчанию равен $[\п";
print "Позиция первого вхождения подстроки '$SUBSTR'
в строку '$STR' = ",index($STR, $SUBSTR), "\n"; print "Позиция первого после позиции $POS вхождения подстроки '$SUBSTR'
в строку '$STR' = ",index($STR, $SUBSTR, $POS), "\n"; print "Позиция последнего вхождения подстроки '$SUBSTR'
в строку '$STR1 = ",rindex($STR, $SUBSTR), "\n"; print "Позиция последнего перед позицией $POS вхождения подстроки '$SUBSTR'
в строку '$STR' = ",rindex($STR, $SUBSTR, $POS), "\n";
$[=2;
print "ХпИндекс первого символа строки по умолчанию изменен на $[\п"; print "Позиция первого вхождения подстроки '$SUBSTR'
в строку '$STR' = ",index($STR, $SUBSTR), "\n"; print "Позиция первого после позиции $POS вхождения подстроки '$SUBSTR'
в строку '$STR' = ",index($STR, $SUBSTR, $POS), "\n";
print "Позиция последнего вхождения подстроки '$SUBSTR' в строку '$STR' = ",rindex($STR, $SUBSTR), "\n";
print "Позиция последнего перед позицией $POS вхождения подстроки '$SUBSTR' в строку '$STR' = ",rindex($STR, $SUBSTR, $POS), "\n";
В результате выполнения скрипта будут выведены следующие строки:
Индекс первого символа строки по умолчанию равен О Позиция первого вхождения подстроки 'безумный'
в строку 'Этот безумный, безумный, безумный, безумный мир!' = 5 Позиция первого после позиции 7 вхождения подстроки 'безумный'
в строку 'Этот безумный, безумный, безумный, безумный мир!' = 15 Позиция последнего вхождения подстроки 'безумный'
в строку 'Этот безумный, безумный, безумный, .безумный мир!' = 35 Позиция последнего перед позицией 7 вхождения подстроки 'безумный'
в строку 'Этот безумный, безумный, безумный, безумный мир!' = 5
Индекс первого символа строки по умолчанию изменен на 2 Позиция первого вхождения подстроки 'безумный1
в строку 'Этот безумный, безумный, безумный, безумный мир!' = 7 Позиция первого после позиции 7 вхождения подстроки 'безумный'
в строку 'Этот безумный, безумный, безумный, безумный мир!' = 7 Позиция последнего вхождения подстроки 'безумный'
в строку 'Этот безумный, безумный, безумный, безумный мир!' = 37 Позиция последнего перед позицией 7 вхождения подстроки 'безумный'
в строку 'Этот безумный, безумный, безумный, безумный мир!' = 7
Функция substrO
substr EXPR, OFFSET [,LENGTH [,REPLACEMENT ]]
извлекает из выражения EXPR подстроку и возвращает ее. Возвращаемая подстрока состоит из LENGTH символов, расположенных справа от позиции OFFSET. Если параметр LENGTH опущен, возвращается вся оставшаяся часть выражения EXPR. Если параметр LENGTH отрицательный, его абсолютное значение задает количество символов от конца строки, не включаемых в результирующую подстроку. Если параметр OFFSET имеет отрицательное значение, смещение отсчитывается с конца строки. Функция substr о может стоять в левой части операции присваивания. Например, в результате выполнения операторов
$Str = "Язык Pascal"; substr($Str, 5,6) = "Perl";
переменная $str получит значение "язык Peri". Тот же результат будет достигнут, если указать параметр REPLACEMENT, значение которого будет подставлено в EXPR вместо выделенной подстроки. Сама подстрока в этом случае возвращается в качестве значения функции substr ().
#!/bin/peri
# Исходная строка
$Str = "Карл у Клары украл кораллы";
$0ffset = 13;
print "Исходная строка:'$Str'\n";
# Смещение 13, длина подстроки не задана
$Substr = substr $Str, $Offset;
print "Смещение $0ffset, длина подстроки не задана, результат:\п";
print "$Substr\n";
# Смещение 13, длина подстроки +5
$Substr = substr $Str, $0ffset, 5;
print "Смещение $0ffset, длина подстроки +5, результат:\п";
print "$Substr\n"; /
# Смещение 13, длина подстроки -1 \
$Substr = substr $Str, $0ffset, -1;
print "Смещение $0ffset, длина подстроки -1, результат:\п";
print "$Substr\n";
# Отрицательное смещение -7, длина подстроки +7
$0ffset = -7;
$Substr = substr $Str, $Offset, 7;
print "Отрицательное смещение $Offset, длина подстроки +7, результат:\п";
print "$Substr\n";
f Отрицательное смещение -7, длина подстроки -1
$Substr = substr $Str, $0ffset, -1;
print "Отрицательное смещение $Offset, длина подстроки -1, результат:\п";
print "$Substr\n";
t Замена подстроки
$Repl = "бокалы";
$Substr = substr $Str,$Offset,7,$Repl;
print "В строке '$Str' слово '$Repl' заменяет слово '$Substr'\n";
Вывод выглядит следующим образом:
Исходная строка:'Карл у Клары украл кораллы'
Смещение 13, длина подстроки не задана, результат:
украл кораллы
Смещение 13, длина подстроки +5, результат:
украл
Смещение 13, длина подстроки -1, результат:
украл коралл
Отрицательное смещение -7, длина подстроки +7, результат:
кораллы
Отрицательное смещение -7, длина подстроки -1, результат:
коралл
В строке 'Карл у Клары украл бокалы' слово 'бокалы' заменяет слово 'кораллы'
Функция eval () eval EXPR
рассматривает параметр EXPR как текст Peri-программы, компилирует его и, если не обнаруживает ошибок, выполняет в текущем вычислительном окружении. Если параметр EXPR отсутствует, вместо него по умолчанию используется глобальная переменная $_. Компиляция программного кода EXPR осуществляется при каждом вызове функции eval () во время выполнения основной программы. Если выполнение мини-программы EXPR завершается успешно, функция eval о возвращает значение последнего выражения, вычисленного внутри EXPR. Если код EXPR содержит синтаксические ошибки, или обращение к функции die (}, или возникла ошибка во время выполнения EXPR, то в специальную переменную $@ помещается сообщение об ошибке, а функция eval () возвращает неопределенное значение.
Замечание Если скалярной переменной не присвоено никакое допустимое значение (число, строка или ссылка), то говорят, что она имеет неопределенное значение. Неопределенные значения возникают в различных случаях, например, при попытке чтения данных после достижения конца файла или в результате системных ошибок. Неопределенное значение представляется пустой строкой "", но его следует отличать от определенного значения, равного "". Например, в результате выполнения операторов
$е = eval '$а = 1/0'; # деление на О
$Ь = "";
print "a= $a\n" if defined $а;
print "e= $e\n" if defined $е;
print "b= $b\n" if defined $b;
переменные $а и $е будут иметь неопределенное значение, а переменная $Ь - определенное значение "".
Для того чтобы определить, имеет выражение EXPR определенное значение или нет, существует функция defined EXPR, возвращающая соответствующее булевское значение. В данном примере результатом выполнения будет вывод единственной строки
b=
Специальная переменная $@ служит для запоминания сообщения об ошибке, возникшей при последнем обращении к функции eval ().
Существует вторая форма функции eval ()
eval BLOCK,
где BLOCK представляет собой блок- последовательность операторов, заключенную в фигурные скобки. Вторая форма отличается от первой тем, что синтаксический анализ параметра BLOCK осуществляется всего один раз - во время компиляции основной программы, содержащей обращение к функции eval (). Таким образом, если параметр BLOCK содержит синтаксические ошибки, то они обнаружатся на этапе компиляции основной программы. При использовании первой формы синтаксические ошибки обнаружатся только во время выполнения.
Основным применением функции eval о является перехватывание исключений. Исключением мы называем ошибку, возникающую при выполнении программы, когда нормальная последовательность выполнения прерывается (например, при делении на нуль). Обычной реакцией на исключение является аварийное завершение программы. Язык Perl предоставляет возможность перехватывать исключения без аварийного выхода. Если исключение возникло в основной программе, то программа завершается. Если ошибка возникла внутри мини-программы функции eval (), то аварийно завершается только функция eval(), а основная программа продолжает выполняться и может реагировать на возникшую ошибку, сообщение о которой ей доступно через переменную $@.
В следующем примере функция eval о применяется для перехватывания ошибки, связанной с делением на 0 при вычислении функции ctg(x). Используются встроенные функции sin, cos и warn. Последняя функция осуществляет вывод сообщения, задаваемого ее аргументом, на стандартное устройство вывода ошибок STDERR.
#!/bin/peri
$fi = 0.314159265358979;
$f = '$ctg = cos($x)/sin($x)
for $i (0..10) {
$x = $i*$fi;
eval $f;
print "x= $x ctg(x) = $ctg\n" if defined $ctg;
warn "x= $x ", $@ if not defined $ctg; };
Вывод программы выглядит следующим образом
х= 0 Illegal division by zero at (eval 1) line 1. x= 0.314159265358979 ctg(x) =3.07768353717526 x= 0.628318530717958 ctg(x) = 1.37638192047118
Замечание Иногда бывает полезно искусственно вызвать исключительную ситуацию. Для этого можно воспользоваться функцией die () LIST. Назначение функции die () - генерировать исключения. Если функция die () вызывается в основной программе вне функции eval (), то она осуществляет аварийное завершение основной программы и выводит сообщение об ошибке LIST на стандарт* ное устройство вывода ошибок STDERR. Если она вызывается внутри функции eval (), то осуществляет аварийное завершение eval () и помещает сообщение об ошибке в специальную переменную $@.
Функция pos()
pos [$SCALAR]
возвращает позицию, в которой завершился последний глобальный поиск $scALAR=~m/.../g, осуществленный в строке, задаваемой переменной $SCALAR. Возвращаемое значение равно числу length($') + length($&). Следующий глобальный поиск m/.../g в данной строке начнется именно с этой позиции.
Если аргумент $ SCALAR отсутствует, возвращается позиция завершения последнего глобального поиска, осуществленного в строке $_.
$words = "one two three four"; while ($words =~ m/\w+/g) {
print "pos=",pos($words)," length(\$~)=",length($'),
" length(\$s)=",length($s),"\n"; }
В результате выполнения данного скрипта будут выведены номера позиций, соответствующих окончаниям слов в строке $words:
pos=3 length($~}=0 length($&)=3
pos=7 length{$')=4 length($&)=3
pos=13 length($~)=8 length($&)=5
pos=18 length($')=14 length($&)=4
Функцию pos () можно использовать в левой части операции присваивания для изменения начальной позиции следующего поиска:
I изменение начальной позиции для последующего поиска
$words = "one two three four";
pos $words = 4;
while ($words =~ m/\w+/g) {
print pos $words, "\n"; }
В последнем случае поиск слов начнется со второго слова, и будут выведены номера позиций 7, 13 и 18.
ФУНКЦИЯ quotemeta () quotemeta [EXPR]
возвращает строку EXPR, в которой все символы, кроме алфавитно-цифровых символов и символа подчеркивания "_", экранированы символом "\". Например, в результате выполнения
print quotemeta "*****", "\n";
будет выведена строка
\*\*\*\*\*
Если аргумент EXPR отсутствует, вместо него используется переменная $_.
Вопросы для самоконтроля
1. Что такое регулярное выражение?
2. Какие символы имеют в регулярном выражении Perl специальное значение?
3. Что такое метапоследовательность, как она образуется?
4. Что такое обратная ссылка?
5. Какая переменная используется в операции подстановки по умолчанию?
6. Какой смысл имеет символ "$" в следующих регулярных выражениях:
/abc*$/
/[аЬс*$]/
/$abc/
7. Какой смысл имеет символ "А" в следующих регулярных выражениях:
/лаЬс/
/ГаЬс]/
/аЬсл/
8. Объясните, какие множества строк соответствуют следующим образцам. Приведите пример.
/a.out/
/a\.out/
/\d{2,3}-\d{2}-\d{2}/
/(.)(.).\2\1/ /(.) (.).\02\01/
9. Напишите образец, задающий палиндром из шести букв.
10. Напишите команду замены, которая:
- заменяет все символы новой строки пробелами;
- выделяет из полного маршрутного имени файла имя файла;
- выделяет из полного маршрутного имени файла имя каталога.
11. Каково значение следующих выражений, если значение переменной
$var равно "123qwerty"? $var =~ /./ $var =- /[A-Z]*/ $var =~ /\w{4-9}/ $var =~ /(\d)2(\D/ $var =~ /qwerty$/ $var =~ /123?/
11. Какое значение будет иметь переменная $var после следующих операций подстановки, если ее начальное значение равно "qwertyi23qwerty"?
$var =~ s/qwerty/XYZ/; $var =~ s/[a-zJ+/X/g; $var =~ s/B/W/i; $var =~ s/(.)\d.*\l/d/; $var =~ s/(\d+)/$l*2/e;
12. Начальное значение переменной $var равно "qwertyi23qwerty". Каким оно будет после выполнения операций транслитерации?
$var =~ tr/a-z/A-Z/; $var =~ tr/a-z/0-9/; $var =~ tr/a-z/O-9/d; $var =~ tr/231/564/; $var =~ tr/123/ /s; . $var =~ tr/123//cd;
13. Переменная $var имеет значение "qwertyqwerty". Каково значение, возвращаемое функцией?
substr ($var, 0, 3);
substr ($var, 4);
substr ($var, -2, 2);
substr ($var, 2, 0) ;
index ($var, "rt"); index ($var, "rtyu"); index ($var, "er", 1); index ($var, "er", 7); rindex ($var, "er");
Упражнения
1. Напишите программу, которая читает стандартный ввод, умножает каждое встретившееся число на 2 и выводит результирующую строку.
2. Напишите программу, которая читает стандартный ввод, удваивает каждую букву и выводит результирующую строку.
3. Напишите программу, подсчитывающую, сколько раз каждый алфавитно-цифровой символ встретился во вхбдном файле.
4. Напишите программу, которая считывает строку из стандартного файла ввода, меняет в ней порядок следования символов на обратный и выводит результат.
5. Напишите программу, которая выполняет преобразование русского текста из одной системы кодировки в другую:
(Dos 866, Windows 1251, UNIX KOI8} <=> (Dos 866, Windows 1251, UNIX, KOI8}
Для выполнения задания можно воспользоваться табл. 10.3, содержащей шестнадцатеричные коды символов русского алфавита.
Таблица 10.3. Таблицы кодов русского алфавита
Символ
866
1251
KOI8
Символ
866
1251
KOI8
А
80
СО
Е1
а
АО
ЕО
С1
Б
81
С1
Е2
б
А1
Е1
С2
В
82
С2
F7
в
А2
Е2
D7
Г
83
СЗ
Е7
г
A3
ЕЗ
С7
Д 84 С4 Е4 Д А4 Е4 С4
Е
85
С5
Е5
е
А5
Е5
С5
Ё
FO
А8
ВЗ
е
F1
В8
A3
Ж
86
С6
F6
ж
А6
Е6
D6
3
87
С7
FA
3
А7
Е7
DA
И
88
С8
Е9
и
А8
Е8
С9
И
89
С9
EA
Й
А9
Е9
СА
К
8А
СА
EB
к
АА
ЕА
СВ
Л
8В
СВ
EC
л
АВ
ЕВ
СС
М
8С
СС
ED
M
АС
ЕС
CD
Н
8D
CD
ЕЕ
Н
AD
ED
СЕ
О
8Е
СЕ
EF
0
АЕ
ЕЕ
CF
П
8F
CF
FO
П
AF
EF
DO
Р
90
DO
F2
Р
ЕО
FO
D2
С
91
D1
F3
с
Е1
F1
D3
Т
92
D2
F4
т
Е2
F2
D4
У
93
D3
F5
У
ЕЗ
F3
D5
ф
94
D4
E6
ф
Е4
F4
С6
X
95
D5
E8
X
Е5
F5
С8
Ц
96
D6
E3
ц
Е6
F6
СЗ
ч
97
D7
FE
Ц
Е7
F7
DE
ш
98
D8
FB
ш
Е8
F8
DB
Щ
99
D9
FD
Щ
Е9
F9
DD
ъ
9А
DA
FF
ъ
ЕА
FA
DF
ы
9В
DB
F9
ы
ЕВ
FB
D9
ь
9С
DC
F8
ь
ЕС
FC
D8
э
9D
DD
FC
э
ED
FD
DC
ю
9Е
DE
EO
ю
ЕЕ
FE
СО
я
9F
DF
F1
я
EF
FF
D1