Работа со строками


Регулярные выражения


Язык, созданный первоначально с главной целью — облегчить обработку большого количества отчетов, просто обязан располагать развитыми средствами для работы с текстом. Напомним, что в среде UNIX, из которой вышел язык Perl, средства для обработки текстовых строк имеются в различных утилитах: sed, awk, grep, cut. Командный интерпретатор shell, также обладающий некоторыми средствами для обработки строк, позволяет организовать совместную работу этих утилит, передавая выход одной программы на вход другой через механизм, называемый конвейером. Такой подход требует написания достаточно изощренных скриптов на языке shell в сочетании с обращением к внутренним командам утилит обработки текста sed или awk. Язык Perl, являясь средством создания программ-сценариев, в то же время один обладает всеми возможностями перечисленных утилит и даже их превосходит.
Типичная задача, возникающая при обработке текстового файла, заключается в том, чтобы найти в нем фрагмент, удовлетворяющий заданным условиям, и выполнить над ним некоторую операцию: удалить, заменить на другой фрагмент, извлечь для дальнейшего использования и т. д. Условия поиска можно достаточно просто выразить словами. Например: найти строку, содержащую слово Perl. Или: найти все фрагменты, находящиеся в конце строки и содержащие две цифры, за которыми следует произвольное количество прописных букв. Для формализованной записи подобных условий используются регулярные выражения, позволяющие описать образец или шаблон поиска при помощи специальных правил. Манипуляции с регулярными выражениями осуществляются при помощи соответствующих операций, которые мы также рассмотрим в этой главе.
Регулярное выражение, по сути, представляет собой набор правил для описания текстовых строк. Сами правила записываются в виде последовательности обычных символов и метасимволов, которая затем в качестве образца используется в операциях поиска и замены текста. Метасимволы — это символы, имеющие в регулярном выражении специальное значение. Пользователи DOS/Windows хорошо знают метасимвол *, используемый для порождения имен файлов и обозначающий любую допустимую последовательность. Регулярные выражения применяются многими программами UNIX, в том числе интерпретатором shell. Каждая из них использует свое множество метасимволов. В большинстве случаев они совпадают.
Метасимволы
В языке Perl к Метасимволам относятся следующие символы:
"\", ".", "^", "$", "|", "[", "(", ")", "*", "+", "?", "}".
Различные метасимволы выполняют в регулярном выражении различные функции, в частности, используются для обозначения одиночного символа или их группы, обозначают привязку к определенному месту строки, число возможных повторений отдельных элементов, возможность выбора из нескольких вариантов и т. д.
Регулярное выражение, подобно арифметическому выражению, строится с соблюдением определенных правил. В нем можно выделить операнды (элементы) и операции.
Простейшее регулярное выражение состоит из одного обычного символа. Обычный символ в регулярном выражении представляет самого себя. Соответственно, последовательность обычных символов представляет саму себя и не нуждается в дополнительной интерпретации. Для использования в операциях в качестве образца регулярное выражение заключается между двумя одинаковыми символами-ограничителями. Часто в качестве ограничителя используется символ "/" (косая черта). Например, образцу /Peri/ будут соответствовать все строки, содержащие слово Perl.
Если, в регулярном выражении какой-либо метасимвол требуется использовать в буквальном, а не специальном значении, его нужно экранировать или маскировать при помощи другого метасимвола — "\". Например, образцу /\\\*/ соответствует фрагмент текста \*. Здесь первый метасимвол "\" экранирует второй метасимвол "\", а третий метасимвол "\" экранирует метасимвол "*".
Метасимвол "." представляет любой одиночный символ, кроме символа новой строки. Так, образцу /./ будет соответствовать любая непустая строка. Если в операциях сопоставления с образцом установлен флаг s, то метасимволу "." соответствует также и символ новой строки.
Метасимвол "[" используется в конструкции [...] для представления любого одиночного символа из числа заключенных в скобки, т. е. он представляет класс символов. Два символа, соединенные знаком минус, задают диапазон значений, например, [A-za-z] задает все прописные и строчные буквы английского алфавита. Если первым символом в скобках является символ " ^ ", вся конструкция обозначает любой символ, не перечисленный в скобках. Например, [ ^ о-9] обозначает все нецифровые символы. Ниже мы рассмотрим и другие способы представления классов символов.
Метасимволы " ^ " и "$" используются для задания привязки к определенному месту строки. Метасимвол " ^ " в качестве первого символа регулярного выражения обозначает начало строки. Метасимвол "$" в качестве последнего символа регулярного выражения обозначает конец строки. Например, следующим образцам соответствуют:
/ ^ $/ — пустая строка (начало и конец, между которыми пусто); / ^ рег1/ — слово Perl в начале строки; /Per 1$/ —слово Perl в конце строки.
Метасимвол "|" можно рассматривать как символ операции, задающей выбор из нескольких вариантов (подобно логической операции ИЛИ). Например, образцу /а|Ь|с/ соответствует фрагмент текста, содержащий любой из символов а, Ь, с, Если вариантами выбора являются одиночные символы, как в данном примере, то лучше использовать конструкцию, определяющую класс символов, в данном случае [abc]. Но в отличие от конструкции [...] операция "|" применима и тогда, когда вариантами выбора являются последовательности символов. Например, образцу /Word|Excel!windows/ соответствует фрагмент^текста^содержащий любое из слов Word, Excel, Windows.
Следующая группа метасимволов служит в качестве коэффициентов или множителей, определяющих количество возможных повторений отдельных атомарных элементов регулярного выражения.

  • r* — нуль и более повторений
  • r+— одно и более повторений
  • r? нуль или одно повторение
  • r{n} ровно п повторений
  • r{n}, — n и более повторений
  • r{n,m} — минимум n, максимум m повторений r

Атомарные элементы, или атомы — это простейшие элементы, из которых строится регулярное выражение. Это не обязательно одиночный символ.
Образец Соответствие
/•*/ любая строка;
/• + / любая непустая строка;
/ [ о-9 ] {з} / любая последовательность из трех цифр;
/\ [ +/ последовательность, состоящая из любого числа символов [.
В первых двух примерах атомом является метасимвол ".". В третьем образце в качестве атома выступает конструкция [0-9], определяющая класс цифровых символов. В четвертом образце атом — это пара символов "\[", включающая метасимвол "\", отменяющий специальное значение следующего за ним метасимвола "[". Полный список атомов мы приведем после изучения всех необходимых синтаксических конструкций.
Алгоритм, применяемый в операциях поиска и замены (см. ниже) для обработки регулярных выражений, содержащих множители, является "жадным": он пытается найти для образца, снабженного множителем, максимальный сопоставимый фрагмент текста. Рассмотрим, например, что происходит при поиске в строке
"Скроен колпак не по-колпаковски, надо колпак переколпаковать" фрагмента, удовлетворяющего образцу /. * колпак/.
Алгоритм найдет максимальный фрагмент, удовлетворяющий выражению . * (вся строка без завершающего символа новой строки), затем начнет двигаться назад, отбрасывая в найденном фрагменте по одному символу, до тех пор, пока не будет достигнуто соответствие с образцом. Найденный фрагмент будет иметь вид "Скроен колпак не по-колпаковски, надо колпак переколпак".
Можно заставить алгоритм работать иначе, снабдив множитель "*" модификатором "?". В этом случае алгоритм из "жадного" превращается в "ленивый" и будет для образца, снабженного множителем, искать минимальный соответствующий фрагмент. "Ленивый" алгоритм для множителя "*?" начнет поиск в строке с пустого фрагмента "", добавляя к нему по одному символу из строки до тех пор, пока не достигнет соответствия с образцом. В этом случае найденный фрагмент будет иметь вид "Скроен колпак". Все сказанное справедливо и для других множителей. Например, в строке "1234567" будет найден:

  • для образца /\d*/ — максимальный фрагмент "1234567";
  • для образца /\d+/ — максимальный фрагмент "1234567";
  • для образца /\d?/ — максимальный фрагмент "1";
  • для образца /\d{2,5}/ — максимальный фрагмент "12345";
  • для образца /\d*?/ — минимальный фрагмент "";
  • для образца /\d+?/ — минимальный фрагмент "1";
  • для образца /\d??/ — минимальный фрагмент "";
  • для образца /\d{2,5}?/ — минимальный фрагмент "12".

Метапоследовательности
Символ "\", непосредственно предшествующий одному из метасимволов, отменяет специальное значение последнего. Если же "\" непосредственно предшествует обычному символу, то, напротив, такая последовательность во многих случаях приобретает специальное значение. Подобного рода последовательности будем называть метапоследователъностями. Метапоследова-тельности в регулярном выражении служат, в основном, для представления отдельных символов, их классов или определенного места в строке, дополняя и иногда дублируя/функции метасимволов. Рассмотрим существующие метапосл едовател ьности.

  • \nnrt — представляет\символ, восьмеричный код которого равен лил. Например, последовательность \120\145\162\154 представляет слово Perl (\120 — восьмеричный код буквы Р, \145 — буквы е, \1б2 — буквы г, \154- буквы!);
  • \хпп — представляет символ, шестнадцатеричный код которого равен пп. Слово Perl, например, представляется последовательностью \x50\x65\х72\хбс;
  • \сп — представляет управляющий символ, который генерируется при нажатии комбинации клавиш <Ctrl>+<N>, где N — символ, например, \со соответствует <Ctrl>+<D>;
  • \$ — символ "$"; G \@ — символ "@"; О \% — символ "%";
  • \а — представляет символ с десятичным ASCII-кодом 7 (звонок). При выводе производит звуковой сигнал;
  • \е — символ Esc, десятичный ASCII-код 27;
  • \f — символ перевода страницы, десятичный ASCII-код 12;
  • \п — символ новой строки, десятичный ASCII-код 10;
  • \г — символ "возврат каретки", десятичный ASCII-код 13;
  • \t — символ горизонтальной табуляции, десятичный ASCII-код 9;
  • \v — символ вертикальной табуляции, десятичный ASCII-код 11;
  • \з — представляет класс пробельных символов. К пробельным символам относятся: пробел, имвол табуляции, возврат каретки, символ новой строки и символ перевода страницы. То же самое, что и [\t,\r,\n,\fj;
  • \s — представляет класс непробельных символов, то же самое, что и класс [ л \t,\r,\n,\f];
  • \d — класс цифровых символов, то же, что и [0-9]; П \о — класс нецифровых символов, то же, что и [ Л о-9];
  • \w — представляет класс буквенно-цифровых символов, состоящий из букв, цифр и символа подчеркивания "_". То же самое, что и [a-zA-z_ o-9j. Обратите внимание, что в этот класс входят только буквы английского алфавита;
  • \w — представляет класс небуквенно-цифровых символов. То же, что и Pa-zA-Z_0-9];
  • \д — обозначает начало строки;
  • \z — обозначает конец строки;
  • \b — обозначает границы слова. Под словом понимается последовательность символов из класса \w. Граница слова определяется как точка между символами из класса \w и символами из класса \w;
  • \B — обозначает не-границы слова, т. е. класс символов [ Л \Ь];
  • \1 — обозначает, что следующий символ регулярного выражения преобразуется к нижнему регистру. Например, запись /\ip/ означает, что символ Р будет преобразован к нижнему регистру, после чего новый образец /р/ может быть использован в соответствующей операции поиска или замены;
  • \n — обозначает, что следующий символ регулярного выражения преобразуется к верхнему регистру;
  • \b.. .\Е — обозначает, что все символы в регулярном выражении между \ь и \Е преобразуются к нижнему регистру;
  • \n.. .\Е — обозначает, что все символы в регулярном выражении между \U и \Е преобразуются к верхнему регистру;
  • \Q...\E— обозначает, что все метасимволы в регулярном выражении между \Q и \Е экранируются при помощи символа "\". Например, запись /\0 Л *?+\Е/ эквивалентна записи /\ Л \*\?\+У;
  • \с — обозначает точку, в которой закончился предыдущий поиск m//g (см. описание операции поиска т//).

Атомы
Из всех метасимволов, перечисленных в начале раздела, нам осталось рассмотреть "(" и "). Эти метасимволы служат для группирования ряда элементов, входящих в состав образца, в один элемент. Например, образцу /<abc)+/ соответствует строка, состоящая из одного или более повторений последовательности abc, в то время, как образцу /abc+/ — строка, состоящая из начальных символов аb, за которыми следует один или более символов с.
Теперь мы можем перечислить "атомы", из которых строится регулярное выражение.

  • Регулярное выражение в скобках, представляющее несколько элементов, сгруппированных в один.
  • Любой обычный символ (не метасимвол).
  • Символ ".", представляющий любой одиночный символ, кроме символа новой строки.
  • Конструкция [...], представляющая класс символов, перечисленных в квадратных скобках.
  • Метапоследовательность, представляющая символ или класс символов: \&, \n, \r, \t, \f, \e, \d, \D, \w, \w, \s, \s.
  • Метапоследовательность вида \nnn, определяющая символ при помощи его восьмеричного ASCII-кода nnn
  • Метапоследовательность вида \хnn, определяющая (символ при помощи его шестнадцатеричного ASCII-кода nn .
  • Метапоследовательность вида \сn, представляющая управляющий символ ctri-n .
  • Конструкция вида \number, представляющая обратную ссылку.
  • Любая конструкция вида \character, не имеющая специального значения, а представляющая собственно символ character, например: \*, \ у , \ь.
  • Напомним, что в регулярном выражении множители *, +, ?, {n,m} применяются именно к атому, расположенному непосредственно слева.

Обратные ссылки
Ранее мы установили, что группу элементов регулярного выражения можно заключить в скобки и рассматривать как один элемент. Заключение группы элементов в скобки имеет дополнительный и весьма полезный эффект. Если в результате поиска будет найден фрагмент текста, соответствующий образцу, заключенному в скобки, то этот фрагмент сохранится в специальной переменной. Внутри регулярного выражения к нему можно будет обратиться, используя запись \number, где number—номер конструкции () в исходном регулярном выражении. Запись \number, указывающую на найденный по образцу фрагмент текста, будем называть обратной ссылкой. Можно задать любое количество конструкций вида () и ссылаться на соответствующие найденные фрагменты текста, как на \i, \2 и т. д. Например, образцу /(. + ) -\1/ соответствуют слова "ха-ха", "хи-хи", "ку-ку" и т. п., а образцу /{.)(.). ?\2\1/ — все палиндромы из четырех или пяти букв. (Палиндром — слово или предложение, которое одинаково читается слева направо и справа налево.)
Внутри образца конструкция \n (n=i,...,9) всегда обозначает обратную ссылку. Запись вида \пп также интерпретируется как обратная ссылка, но только в том случае, если в исходном выражении задано не менее, чем пп скобочных конструкций вида (). Иначе запись \пп обозначает символ с восьмеричным кодом nn.
Для ссылки на найденный фрагмент текста за пределами регулярного выражения, например, при задании замещающего текста в операции замены, вместо записи \number используется запись $пшпЬег. Например, операция замены
$str=~s/(\S+)\s+(\S+)/$2 $1/
меняет местами первые два слова в строке $str.
Область действия переменных $1, $2 и т. д, распространяется до наступления одного из следующих событий: конец текущего блока; конец строки, являющейся аргументом функции evai; следующее совпадение с образцом. Аналогичным образом определяется область действия и для следующих предопределенных переменных, используемых в операциях сопоставления с образцом.

  • $& — часть строки, найденная при последней операции сопоставления с образцом.
  • $' — часть строки, стоящая перед совпавшей частью при последней успешной операции сопоставления с образцом.
  • $' — часть строки, стоящая после совпавшей части при последней успешной операции сопоставления с образцом.

Например, в результате выполнения операции поиска
$str=~m/two/
в строке $str="one two three" образца /two/ переменным будут присвоены следующие значения:
$& - "two"; $* - "one"; $' - "three".
Эти значения будут сохраняться до наступления одного из перечисленных выше событий, и их можно использовать, например, для формирования строки с обратным порядком следования слов: $rstr=$'.$&.$". Строка $rstr будет иметь ВИД "three two one".
Следует отметить, что, если обращение к одной из переменных $&, $', $• встречается где-либо в программе, то интерпретатор peri будет вычислять и запоминать их для каждой операции сопоставления с образцом, что, в свою очередь, замедляет выполнение всей программы. Поэтому не следует использовать данные переменные без особой необходимости.
Расширенный синтаксис регулярных выражений
Выше мы использовали скобки для группирования нескольких элементов регулярного выражения в один элемент. Побочным эффектом данной операции является запоминание найденного фрагмента текста, соответствующего образцу, заключенному в скобки, в специальной переменной. Если скобки используются только для группирования элементов регулярного выражения, то найденный фрагмент текста можно не запоминать. Для этого после открывающей скобки "(" следует поместить конструкцию "?:", например, в случае задания альтернативы / (?: pattern) /.
?:pattern
Конструкция относится к классу конструкций общего вида (?...), добавляющих новые возможности для задания образцов за счет расширения синтаксиса регулярного выражения, а не за счет введения новых метасимволов или метапоследовательностей. Символ, следующий за символом "?", опреде- , ляет функцию, выполняемую данной синтаксической конструкцией. В на^ стоящее время определены около десяти расширенных конструкций регулярного выражения, большая часть которых рассмотрена в данном разделе. Оставшиеся конструкции, на наш взгляд, не являются необходимыми для первоначального знакомства с языком.
(?#text)
Текст после символа tt и до закрывающей скобки ), комментарий, игнорируется интерпретатором и используется для добавления непосредственно в регулярное выражение.
(?:pattern)
(?imsx-imsx:pattern)
Использовать скобки только для группирования элементов без создания обратных ссылок. Символы imsx-imsx между вопросительным знаком и двоеточием интерпретируются как флаги, модифицирующие функцию данного выражения (см. ниже).
(?=pattern)
Следующий фрагмент в тексте должен соответствовать образцу pattern. Обычно образец для операций поиска или замены задается при помощи регулярного выражения. Результатом операции поиска является фрагмент, соответствующий образцу, который сохраняется в специальной переменной $&. Конструкция (?=pattern) в составе регулярного выражения позволяет задать условие поиска, не включая найденный фрагмент, соответствующий образцу pattern, в результат, сохраняемый в переменной $&. Конструкция (?=pattern) в регулярном выражении задает условие, что следующий фрагмент текста должен удовлетворять образцу pattern. Обращаем внимание на слово следующий. Данная конструкция неприменима для задания условия, что предыдущий фрагмент текста должен соответствовать заданному образцу. Например, образцу /b+(?=с+)/ соответствует часть строки, состоящая из одной или более литер ь, за которыми следуют одна или более литер с, причем найденный фрагмент текста будет содержать только последовательность литер ь без последовательности литер с.
Рассмотрим строку
$str = "aaabbbcccddd";
В результате операции поиска
$str =~ m/b+(?=c+)/;
будут сохранены следующие значения в специальных переменных:
$ ч — ааа $& - bbb $' — cccddd
Если в операции поиска указать образец /b+с+/, то значения специальных переменных будут следующими:
$" — ааа $& — bbbссс $' - ddd
В свою очередь, операция поиска по образцу / (?=b+) с+/ в нашем примере не даст результата. Данный образец задает условие, что следующий фрагмент текста должен содержать непустую последовательность литер ь. В нашей строке такой -фрагмент будет найден (это фрагмент bbb>, но не будет включен в результат поиска. Следующий фрагмент, в соответствии с образцом, должен представлять непустую последовательность литер с, но в нашем случае этого соответствия не будет, так как мы остановились перед фрагментом ььь, не включив его в результат, и поэтому следующим фрагментом будет bbb, а не ссс.
Конструкцию (?=pattern) будем называть регулярным выражением с положительным постусловием.
(?!pattern)
Конструкция (? [pattern) в регулярном выражении задает условие, что следующий фрагмент текста не должен удовлетворять образцу pattern. Найденный фрагмент не запоминается в переменной $&. Например, результат операции поиска
$str =~ m/b+(?!c+)/;
в рассмотренной выше строке $str будет зафиксирован в следующих значениях специальных переменных:
$' — ааа
$& - bb
$' — bcccddd
Найденная подстрока соответствует образцу: она состоит из двух литер ьь, за которыми не следует последовательность литер с.
По аналогии с предыдущей данную конструкцию назовем регулярным выражением с отрицательным постусловием.
(?<=pattern)
Конструкция (?<=pattern) в регулярном выражении задает условие, что предыдущий фрагмент текста должен удовлетворять образцу pattern. Найденный фрагмент не запоминается в переменной $&. Образец pattern должен иметь фиксированную длину, т. е. не содержать множителей.
В нашем примере в результате операции поиска
$str =~ m/(?<=b)b+/;
значения специальных переменных будут распределены следующим образом:
$' — aaab
$& - bb
$' - cccddd I
Данную конструкцию назовем регулярным выражением с положительным предусловием. _/
(?<!pattern)
Конструкция (?<! pattern) в регулярном выражении задает условие, что предыдущий фрагмент текста не должен удовлетворять образцу pattern. Найденный фрагмент не запоминается в переменной $&. Образец pattern должен иметь фиксированную длину, т. е. не содержать множителей.
В нашем примере в результате операции поиска
$str =~ m/(?<!b)c+/;
специальные переменные получат следующие значения:
$' — aaabbbc $& — ее $' - ddd
Данную конструкцию будем называть регулярным выражением с отрицательным предусловием.
(?imsx-imsx)
Задание флагов операции сопоставления с образцом осуществляется в самом образце. Флаги модифицируют выполнение операции и обычно являются частью синтаксиса самой операции. Расширенная конструкция (?imsx-imsx) позволяет задать флаги операции внутри самого образца. Эта возможность может быть полезной, например, в таблицах, когда разные элементы таблицы требуется по-разному сопоставлять с заданным образцом, например, некоторые элементы — с учетом регистра, другие — без учета. Допустимыми являются следующие флаги.

  • i — поиск без учета регистра;
  • dm — строка трактуется как мульти-строка, состоящая из нескольких строк, разделенных символом новой строки;
  • s — строка трактуется как одна строка, в этом случае метасимволу "." соответствует любой одиночный символ, включая символ новой строки;
  • х — разрешается использовать в образцах пробелы и комментарии. При использовании флага х пробелы в образцах игнорируются. Признаком комментария является символ #, как и в основном тексте Peri-программы. Пробелы позволяют сделать образец более читаемым.

Одна из литер i, m, s, x после знака "-" обозначает отмену соответствующего флага.
При помощи данной расширенной конструкции можно задать, например, следующий образец
/(?ix) peri # игнорирование регистра при поиске/
Флаг i предписывает не учитывать регистр в операциях сопоставления с образцом, так что образцу будет соответствовать и слово peri, и слово Perl. Флаг х позволяет выделить слово "peri" пробелами и использовать в образце комментарий. И пробелы, и комментарий не будут учитываться в операции сопоставления с образцом.
Сводка результатов
Изложенное в данном разделе можно суммировать в виде набора правил, которыми следует руководствоваться при работе с регулярными выражениями.

  • Любой одиночный символ, не являющийся метасимволом, представляет самого себя.
  • Специальное значение метасимвола можно отменить, поместив перед ним специальный экранирующий метасимвол "\".
  • Можно определить класс символов, заключив их в квадратные скобки. Если первым после открывающей скобки "[" является символ " ^ ", то вся конструкция обозначает символы, не перечисленные в скобках. Внутри скобок два символа, соединенные знаком "-", определяют диапазон. Чтобы включить в состав класса символ "-", его следует поместить в начале или в конце списка, или экранировать при помощи символа "\".
  • Символы можно задавать при помощи метапоследовательностей, состоящих из символа "\", за оторым следует обычный символ или последовательность символов.
  • Альтернативный выбор задается перечислением альтернативных вариантов, разделенных символом "|". Обычно вся конструкция при этом заключается в круглые скобки.
  • Внутри регулярного выражения можно выделить подобразец, заключив его в круглые скобки. На и-ю конструкцию в скобках можно затем сослаться, используя нотацию \п внутри и $п — вне регулярного выражения.

В заключение раздела приведем в табл. 10.1 и 10.2 сводку метасимволов и метапоследовательностей, рассмотренных в данной главе.
Таблица 10.1. Символы, имеющие специальное значение у в регулярных выражениях Perl

Таблица 10.2. Метапоследовательности в регулярных выражениях Perl

Операции с регулярными выражениями
В данной главе неоднократно упоминались операции с регулярными выражениями, такие как поиск по образцу. Основными среди них являются: операция поиска т//, операция замены s/// и операция транслитерации tr///.
Операция поиска
m/PATTERN/cgimosx
Операция поиска HI/PATTERN/ осуществляет поиск образца PATTERN. Результатом операции является значение 1 (ИСТИНА) или пустая строка"
(ЛОЖЬ). По умолчанию поиск осуществляется в строке, содержащейся в специальной переменной $_. Можно назначить другую строку для поиска в ней заданного образца при помощи операций связывания =~ или ! ~:
$var =~ m/PATTERN/cgimosx
В результате последней операции поиск образца PATTERN будет осуществляться в строке, задаваемой переменной $var. Если в правой части операции связывания стоит операция поиска т//, то в левой части может находиться не обязательно переменная, а любое строковое выражение.
Операция ! ~ отличается от операции =~ тем, что возвращает противоположное логическое значение. Например, в результате поиска в строке "aaabbbccc" образца /b+/Г
$s="aaabbbccc" =~ m/b+/; $s="aaabbbccc" !~ m/b+/;,
в обоих случаях будет найден фрагмент ььь. Но в первом случае возвращаемое значение, сохраненное в переменной $s, будет равно 1 (ИСТИНА), а во втором случае — пустой строке " (ЛОЖЬ).
Образец PATTERN может содержать переменные, значения которых подставляются при каждом выполнении поиска по данному образцу.
Флаги cgimosx модифицируют выполнение операции поиска. Флаги imsx имеют тот же смысл, что и в рассмотренном выше случае конструкции расширенного регулярного выражения (?imsx-imsx) .

  • i — поиск без учета регистра;
  • m — трактуется как мульти-строка, состоящая из нескольких строк, разделенных символом новой;
  • s — строка трактуется как одна строка, в этом случае метасимволу "." со-, ответствует любой одиночный символ, включая символ новой строки;
  • х — разрешается использовать в образцах пробелы и комментарии.
  • стальные флаги выполняют следующие функции.
  • g — Задает глобальный поиск образца в заданной строке. Это означает, что будут найдены все фрагменты текста, удовлетворяющие образцу, а не только первый из них, как имеет место по умолчанию. Возвращаемое значение зависит от контекста. Если в составе образца имеются подоб-разцы, заключенные в скобки (), то в контексте массива для каждого заключенного в скобки подобразца возвращается список всех найденных фрагментов. Если в составе образца нет подобразцов, заключенных в скобки, то в контексте массива возвращается список всех найденных фрагментов, удовлетворяющих образцу. В скалярном контексте каждая операция m//g осуществляет поиск следующего фрагмента, удовлетворяющего образцу, возвращая значение 1 (ИСТИНА), если он найден, и пустую строку ", если не найден. Позиция строки, в которой завершился последний поиск образца при установленном флаге g, может быть получена при помощи встроенной функции роз о (см. ниже). Обычно при неудачном поиске начальная позиция поиска восстанавливается в начало строки. Флаг с отменяет восстановление начальной позиции поиска при неудачном поиске образца.

Рассмотрим следующий скрипт.
$str="abaabbaaabbbaaaabbbb";
tt контекст массива, нет подобразцов в скобках
@result=$str =~m/a+b+/g;
print "контекст массива, нет конструкций в скобках:\n";
print "\@result=@result\n";
# контекст массива, есть конструкции в скобках, задающие обратные ссылки
@result=$Str =~m/(a+)(b+)/g;
print "контекст массива, есть конструкции в скобках:\n";
print "\@result=@result\n";
# скалярный контекст
print "скалярный контекст:\n";
while ($result=$str =~m/(a+)(b+)/g) {
print "result=$result, current match is $&, position=",pos($str),"\n"; }
Результатом его выполнения будет вывод:
контекст массива, нет конструкций в скобках:
@result=ab aabb aaabbb aaaabbbb
контекст массива, есть конструкции в скобках:
@result=a b aa bb ааа bbb aaaa bbbb
скалярный контекст:
result=l, current match is ab, position=2
result=l, current match is aabb, position=6
result=l, current match is 'aaabbb, position=12
result=l, current match is aaaabbbb, position=20

HI с — Используется совместно с флагом g. Отменяет восстановление начальной позиции поиска при неудачном поиске образца.
Рассмотрим скрипт
$str="abaabbaaabbbaaaabbbb";
while ($result=$str =~m/(a+)(b+)/g) {
print "result=$result, current match is $&, position=",pos($str),"\n";
} • print "last position=", pos($str), "\n";
Здесь поиск образца /а+ь+/ в строке $str осуществляется в цикле до первой неудачи. При последнем (неудачном) поиске начальная позиция поиска по умолчанию устанавливается в начало строки, в этом случае вывод имеет вид:
result=l, current match is ab, position=2 result=l, current match is aabb, position=6 result=l, current match is aaabbb, position=12 result=l, current match is aaaabbbb, position=20 last position=
Если глобальный поиск осуществлять при установленном флаге с:
while ($result=$str =~m/ (a+) (b+)/gc) {
то при последнем неудачном поиске начальная позиция поиска не переустанавливается. Вывод имеет вид:
result=l, current match is ab r position=2 result=l, current match is aabb, position=6 result=l, current match is aaabbb, position=12 result=l, current match is aaaabbbb, position=20 last position=20
При задании образца для глобального поиска m//g можно использовать ме-тапоследовательность \с, представляющую точку, в которой закончился последний поиск m//g. Например, в результате выполнения скрипта .
^^х
$str="l) abc 2) aabbcc 3) aaabbbccc 4) aaaabbbbcccc";
$str=~m/3\)\s+/g; \
! $str=~m/\Ga+/; ,'
сначала по образцу будет найден фрагмент "3)", а затем фрагмент, удовлетворяющий образцу /а+/ и расположенный сразу за точкой, в которой завершился последний поиск. Этим фрагментом является "ааа".
По— Значения переменных, входящих в состав образца PATTERN, подставляются только один раз, а не при каждом поиске по данному образцу. Рассмотрим, например, следующий скрипт:
@pattnlist=("a+", "Ы-", "с+", "d+") ; foreach $pattn (@pattnlist) (
$line = <STDIN>; $line =~ m/$pattn/o;
print "pattn=$pattn \$&= $&\n"; }
Массив gpattniist содержит список образцов "a+", "b+", "с+" и "d+". В цикле по элементам этого списка в переменную $iine считывается очередная строка из стандартного ввода. В ней осуществляется поиск по образцу, совпадающему с текущим элементом списка. Поскольку использован флаг о, подстановка значений в образце /$pattn/ будет осуществлена один раз за время жизни данной Peri-программы, т. е. в качестве образца на каждом шаге цикла будет использовано выражение "а+". Если операцию поиска осуществлять без флага о:
$line =~ m/$pattn/,
то в качестве образца будут последовательно использованы все элементы списка "а+", н b+", "с+" и "d+".
В качестве символов-ограничителей для выделения образца можно использовать любую пару символов, не являющихся цифрой, буквой или пробельным символом. Если в качестве ограничителя используется символ "/", то литеру m в обозначении операции можно опустить и использовать упрощенную форму /PATTERN/ BMeCTO m/PATTERN/.
Если в качестве ограничителя используется одинарная кавычка ', то подстановка значений переменных внутри образца не производится.
Если в качестве ограничителя используется символ "?": ?PATTERN?, то при применении операции поиска находится только одно соответствие. Например, в результате выполнения скрипта
$str="abaabbaaabbbaaaabbbb";
while ($result = $str =~ m?a+b+?g) (
print "result=$result, current match is $&, position=", pos($str),"\n";
}
будет найдено только первое соответствие образцу:
result=l, current match is ab, position=2
Операция замены
s/PATTERN/REPLACEMENT/egimosx
Операция замены S/PATTERN/REPLACEMENT/ осуществляет поиск образца PATTERN и, в случае успеха, замену найденного фрагмента текстом REPLACEMENT. Возвращаемым значением является число сделанных замен или пустая строка (ЛОЖЬ), если замен не былоТПо умолчанию поиск и замена осуществляются в специальной переменной $_. Ее можно заменить другой строкой при помощи операций связывания =~ или ! ~:
$var =~ s/PATTERN/REPLACEMENT/egimosx
Флаг $ задает глобальную замену всех фрагментов, удовлетворяющих образцу PATTERN,TeKCTOM REPLACEMENT.
Флаг е означает, что заменяющий текст REPLACEMENT следует рассматривать как Peri-выражение, которое надо предварительно вычислить. Например, в результате выполнения скрипта
$str="abaabbaaabbbaaaabbbb"; $result=$str =~s[ (a+b+)]<length($l)>ge; print "result=$result new str=$str\n";
будет выведено число сделанных замен $ result и новое значение строки $str, в которой каждый найденный фрагмент, соответствующий образцу [а+b+], заменен числом, равным его длине:
result=4 new str=2468
Флаги imosx имеют тот же смысл, что для операции поиска m//.
Так же, как и в операции замены, в качестве ограничителей для выделения образца можно использовать любую пару символов, не являющихся цифрой, буквой или пробельным символом. Можно использовать различные ограничители для выделения образца и замещающего текста, например,
s(pattern)<replacement>.
Операция транслитерации
tr/SEARCHLIST/REPLACEMENTLIST/cds
Преобразует каждый символ из списка поиска SEARCHLIST в соответствующий символ из списка замены REPLACEMENTLIST и возвращает число преобразованных символов. По умолчанию преобразования осуществляются в строке, задаваемой переменной $_. Как и в рассмотренных выше операциях поиска и замены, при помощи операций связывания =~ и ! ~ можно задать для преобразования строку, отличную от принятой по умолчанию
$str =~ tr/SEARCHLIST/REPLACEMENTLIST/cds
Списки SEARCHLIST и REPLACEMENTLIST задаются перечислением символов, могут содержать диапазоны — два символа, соединенных знаком "-", и иметь собственные символы-ограничители, например, tr(a-j) /0-9/. Операция tr/// имеет синонимичную форму, используемую в потоковом редакторе sed:
y/SEARCHLIST/REPLACEMENTLIST/cds
Флаги cds имеют следующий смысл.

  • с — вместо списка поиска SEARCHLIST использовать его дополнение до основного множества символов (обычно расширенное множество ASCII).
  • d — удалить все символы, входящие в список поиска SEARCHLIST, для которых нет соответствия в списке замены REPLACEMENTLIST. Если флаг d не установлен и список замены REPLACEMENTLIST короче, чем список поиска SEARCHLIST, то вместо недостающих символов в списке замены используется последний символ этого списка. Если список замены пуст, то символы из списка поиска SEARCHLIST преобразуются сами в себя, что удобно использовать для подсчета числа символов в некотором классе. П s — все последовательности символов, которые были преобразованы в один и тот же символ, заменяются одним экземпляром этого символа.

$str =~ tr/A-Z/a-z/; # преобразование прописных букв в строчные $count=$str=~tr/\000//c; # подсчет числа символов в строке $str $str =~ tr/\200-\377/ /cs; # любая последовательность символов
с ASCII-кодами от 128 до 255 преобразуется
в единственный пробел
Следующий скрипт преобразует русский текст в DOS-кодировке 866, содержащийся в файле "866.txt", в русский текст в Windows-кодировке 1251, и записывает преобразованный текст в файл "1251. txt".
open(IN866, "866.txt"); open(OUT1251,">125I.txt"); while ($line=<IN866>) { .
$line=~tr/\200-\257\340-\361/\300-\377\250\270/; print OUT1251 $line;
>
close(IN866); close(OUT1251);
Операция заключения в кавычки qr//
qr/STRING/imosx
Операция qr// по своему синтаксису похожа^наГдругие операции заключения в кавычки, такие как q//, qq//, qx//, qw//. Она обсуждается в данном разделе, так как имеет непосредственное отношение к регулярным выражениям. Регулярное выражение, содержащее переменные, метасимволы, мета-последовательности, расширенный синтаксис, перед использованием должно быть обработано компилятором. Операция qr// осуществляет предварительную компиляцию регулярного выражения STRING, преобразуя его в некоторое внутреннее представление, с тем, чтобы сохранить скомпилированное регулярное выражение в переменной, которую затем можно использовать без повторной компиляции самостоятельно или в составе других регулярных выражений.
Преимущества от применения операции qr// проявляются, например, в следующей ситуации. Допустим, что мы собираемся многократно использовать в качестве образца достаточно сложное регулярное выражение, например, / ^ ([ ^ ]*) *([ ^ ]*)/. Его можно использовать непосредственно в операции сопоставления с образцом
if ($line =~ / ^ (Г ]*) *([ ^ ]*)/) {...},
или сохранить в переменной $pattern= ll/^ ([ ^ ]*) *([ ^ ]*) и обращаться к переменной:
if ($line =~ /$pattern/) (...},
В обоих случаях регулярное выражение при каждом обращении обрабатывается компилятором, что при многократном использовании увеличивает время выполнения. Если сохранить образец при помощи операции qr//:
$pattn = qr/~(r ]*) *<Г ]*)/,
то переменная $pattn будет содержать откомпилированное регулярное выражение, которое можно неоднократно использовать без дополнительной компиляции.
Флаги imosx имеют тот же смысл, что и в операции замены т//. Например, в следующем тексте операция qr// применяется с флагами ох:
$s="aA!Bb2cC3Dd45Ee";
@pattns=("\\d+ # последовательность цифр",
"[A-Z]+ t последовательность прописных букв", "[a-z]+ # последовательность строчных букв"); foreach $pattn Opattns) { my $pattern=qr/$pattn/ox; while ($s=~/$pattern/g) { $p=$p.$&; . } } print "s=$s p=$p\n";
В данном примере определен массив @pattns, состоящий из регулярных выражений. В цикле по элементам массива проверяется наличие в заданной строке $з фрагмента, соответствующего текущему образцу. Найденный фрагмент добавляется в конец строки $р. Флаг х в операции qr// позволяет использовать образцы в том виде, в каком они хранятся в массиве — с пробелами и комментариями. Если в операции qr// флаг о не установлен, то в результате выполнения скрипта строка $р будет состоять из символов строки $s, расположенных в следующем порядке: сначала все цифры, затем все прописные буквы, затем все строчные буквы. Если, как в данном ^тексте, флаг о установлен, то в операции $pattern=qr/$pattn/ox подстановка переменной $pattn произойдет только один раз, и строка $s будет три раза проверяться на наличие фрагмента, удовлетворяющего первому образцу $pattns[i]. В результате строка $р будет состоять только из цифр, входящих в строку $s, повторенных три раза.
Функции для работы со строками
В данном разделе мы рассмотрим некоторые встроенные функции языка Perl, предназначенные для работы со строками текста. Часть из них использует рассмотренное выше понятие регулярного выражения.
ФуНКЦИЯ chop () chop [list]
удаляет последний символ из всех элементов списка 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(), Icfirst(), ucfirstO
предназначены для преобразования строчных букв в прописные и наоборот.
ФуНКЦИЯ 1с EXPR
возвращает выражение, полученное из выражения EXPR преобразованием всех символов в строчные.
ФуНКЦИЯ UC EXPR
возвращает выражение, полученное из выражения EXPR преобразованием всех символов в прописные.
ФуНКЦИЯ Icfirst EXPR
возвращает выражение, полученное из выражения EXPR преобразованием первого символа в строчный.
ФуНКЦИИЯ ucfirst EXPR
возвращает выражение, полученное из выражения EXPR преобразованием первого символа в прописной.
#!/usr/bin/perl
print "\n Ф-ция uc() преобразует ",$s="upper case"," в ",uc $s;
print "\n Ф-ция ucfirst() преобразует ",$s="uPPER CASE"," в ",ucfirst $s;
print "\n Ф-ция 1с() преобразует ", $s="LOWER CASE"," в ",1с $s;
print "\n ф-ция IcfirstO преобразует ",$s="Lower case"," в ",lcfirst $s;
В результате выполнения данного скрипта будут напечатаны строки:
Ф-ция uc() преобразует upper case в UPPER CASE Ф-ция ucfirst() преобразует UPPER CASE в UPPER CASE Ф-ция 1с() преобразует LOWER CASE в lower case Ф-ция IcfirstO преобразует Lower case в lower case
ФуНКЦИЯ join() 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). .

#!/usr/bin/perl while (<>) {
print; };
Программа вызвана следующим образом script.pl filel file2 file3
Тогда операция о будет считывать строки сначала из файла filel, затем из файла file2 и, наконец, из файла file3. Если в командной строке файлы не указаны, то в качестве файла ввода будет использован стандартный ввод.
Только в случае, когда условное выражение оператора while состоит из единственной операции "ромб", вводимое значение автоматически присваивается предопределенной переменной $_. Вот что означают слова о том, что переменная $_ применяется для обозначения используемой по умолчанию области ввода. Аналогично обстоит дело с поиском по образцу.
I!/usr/bin/perl while (<>} {
chop;
print "Число полей во входной строке '$_' равно ", $n=split;
print "ХпВходная строка разбита на строки:\n";
foreach $i (@_) {
print $i . "\n"; }
print "Объединение списка строк в одну строку через ' +':\n";
$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

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика