Регулярные выражения
Регулярные выражения позволяют сопоставлять текст с указанным шаблоном (а именно, сравнивать две строки
с помощью универсальных символов, интерпретируемых специальным образом) и выполнять замену текста.
В Perl имеются три основных оператора, работающих со строками:
# m/.../ — проверка совпадений (matching),
# s/.../.../ — подстановка текста (substitution),
# tr/.../.../ — замена текста (translation).
Оператор m/.../ анализирует входной текст и ищет в нем подстроку, совпадающую с указанным шаблоном.
Оператор s/.../.../ выполняет подстановку одних текстовых фрагментов вместо других.
Оператор tr/.../.../ осуществляет замену посимвольно.
В следующем примере ищем подстроку exit :
if ($line =~ m/exit/i) {exit;}
Префикс /i указывает на то , что регистр символов в переменной $line не имеет значения.
Начальную букву m в операторе сравнения можно опустить.
Можно использовать вместо / другие разграничители , но тогда прийдется писать m :
if ($line =~ /exit/i) {exit;}
if ($line =~ m|quit|i) {exit;}
if ($line =~ m%stop%i) {exit;}
В следующем случае мы заменяем подстроку young на подстроку old:
$text = "Pretty young.";
$text =~ s/young/old/;
Операторы s/.../.../ и m/.../ ведут поиск и замену с первого символа текстовой строки до первого совпадения.
Если оно найдено, без специального указания поиск не продолжается:
Оператор tr/.../.../ заменяет один символ на другой ,
$text = "His name is Tom.";
$text =~ tr/o/i/;
В Perl операторы tr/.../.../ и y/.../.../ выполняют одинаковые действия
Рассмотрим регулярные выражения . В общем случае они состоят из следующих компонентов :
# одиночные символы (characters)
# классы символов (character classes)
# альтернативные шаблоны (alternative match patterns)
# квантификаторы (quantifiers)
# мнимые символы (assertions)
# ссылки на найденный текст (backreferences)
# дополнительные конструкции (regular expression extensions).
Perl определяет специальные символы. Они вводятся с помощью обратной косой черты (escape-последовательности)
и также могут встречаться в регулярном выражении:
# \077 — восьмиричный символ
# \a — символ BEL (звонок)
# \c[ — управляющие символы (комбинация Ctrl + символ,
в данном случае — это управляющий символ ESC)
# \d — соответствует цифре
# \D — соответствует любому символу, кроме цифры
# \e — символ escape (ESC)
# \E — конец действия команд \L, \U и \Q
# \f — символ прогона страницы (FF)
# \l — следующая литера становится строчной (lowercase)
# \L — все последующие литеры становятся строчными вплоть до команды \E
# \n — символ новой строки (LF, NL)
# \Q — вплоть до команды \E все последующие метасимволы становятся
обычными символами
# \r — символ перевода каретки (CR)
# \s — соответствует любому из пробельных символов
(пробел,вертикальная или горизонтальная табуляция,символ новой строки)
# \S — любой символ, кроме «пробельного»
# \t — символ горизонтальной табуляции (HT, TAB)
# \u — следующая литера становится заглавной (uppercase)
# \U — все последующие литеры становятся заглавными вплоть до команды \E
# \v — символ вертикальной табуляции (VT)
# \w — алфавитно-цифровой символ (любая буква, цифра или символ подчеркивания)
# \W — любой символ, кроме букв, цифр и символа подчеркивания
# \x1B — шестнадцатиричный символ
В следующем примере Here будет заменено на There с помощью шаблона \w+
$text = "Here is some text.";
$text =~ s/\w+/There/;
print $text;
There is some text.
С помощью символа точка все символы в строке заменяются на звездочку :
$text = "Now is the time.";
$text =~ s/./*/g;
Символы могут быть сгруппированы в классы .Класс - список символов , заключенный в квадратные скобки .
Можно указывать как отдельные символы , так и диапазон Следующий код производит поиск гласных :
$text = "Here is the text.";
if ($text =~ /[aeiou]/) {print "Yesss.\n";}
C помощью шаблона [A-Za-z]+ (метасимвол + означает утверждение: «один или более таких символов» )
ищется и заменяется первое слово:
$text = "What is the subject.";
$text =~ s/[A-Za-z]+/Perl/;
print $text;
Perl is the subject.
Если сразу после открывающей квадратной скобки стоит символ ^, то смысл меняется на противоположный -
а именно, этот класс сопоставляется любому символу, кроме перечисленных в квадратных скобках.
В следующем примере производится замена фрагмента текста, составленного не из букв и не из пробелов:
$text = "Perl is the subject on page 493 of the book.";
$text =~ s/[^A-Za-z\s]+/500/;
print $text;
Perl is the subject on page 500 of the book.
Вы можете задать несколько альтернативных шаблонов, используя символ | как разделитель.
Например, следующий фрагмент проверяет на «exit», «quit» или «stop» одновременно:
if ($line =~ m/exit|quit|stop/) {exit;}
Конструкция [Tim|Tom|Tam] будет эквивалентна классу символов [Tioam|].
Квантификаторы указывают на то, что тот или иной шаблон в строке может повторяться определенное количество раз.
Например, можно использовать квантификатор + для поиска мест неоднократного повторения подряд латинской буквы e
и их замены на одиночную букву e:
$text = "Hello from Peeeeeeeeeeeeeeerl.";
$text =~ s/e+/e/;
print $text;
Hello from Perl.
Проверка на то , что в строке не менее 20 символов :
if ($line =~ !m/.{20,}/) {print "Please type longer lines!\n";}
В Perl имеются символы (метасимволы), которые соответствуют не какой-либо литере или литерам,
а означают выполнение определенного условия (поэтому в английском языке их называют assertions,или утверждениями).
# . — соответствует любому символу кроме новой строки
# ^ — начало строки текста,
# * — совпадение 0 или более раз
# + — совпадение 1 или более раз
# ? — совпадение 0 или 1 раз
# (n) — совпадение точно n раз
# (n,) — совпадение меньше или равно n раз
# (n,m) — совпадение минимум n раз но не более чем m раз
# | — чередование (соответствует "left|right|up|down|sideways")
# $ — конец строки или позиция перед символом начала новой строки,
расположенного в конце,
# \b — граница слова,
# \B — отсутствие границы слова,
# \A — «истинное» начало строки,
# \Z — «истинный» конец строки или позиция перед символом
начала новой строки, расположенного в «истинном» конце строки,
# \z — «истинный» конец строки,
Пример:
Пусть у нас имеется список :
Anne Bonney
Bartholomew Roberts
Charles Bellamy
Diego Grillo
Edward Teach
Francois Gautier
George Watling
Henry Every
Israel Hands
John Derdrake
KuoHsing Yeh
В каждой строке этого списка требуется заменить 1-е слово на 'Captain'.
s/^.+ /Captain /;
В данном решении символ ^ соответствует началу строки , .+" - для каждого символа более 1 раза,
Теперь посложнее - поменяем в каждой строке имя и фамилию , и в начале каждой строки будет
идти Captain :
s/^(\w*) (\w*)$/Captain $2, $1/;
Пример:
Рассмотрим фразу :
Acciones son amores, no besos ni apachurrones
Шаблон /A.*es/ будет соответствовать целиком всей этой фразе.
А вот шаблон /A.*?es/ будет соответствовать Acciones
В следующем примере выводится сообщение о том, что переменная = «yes», при условии что оно единственное.
Для этого шаблон включает мнимые символы начала и конца строки:
if ($line =~m/^yes$/) { print "Yesss.\n";
Следующий пример позволяет выделять текст, расположенный между любыми правильно закрытыми метками:
$text = "Here is an anchor.";
if ($text =~ m%<([A-Za-z]+)>[\w\s\.]+\1>%i) {
print "HTML tag with some text inside it is found.";}
Пример: разбить целое число на триады , т.е. разбить его на группы по 3 цифры , разделенные пробелом :
$number=112341234526.24;
$number=triada($number);
print $number;
sub triada() {
$str=$_[0];
$res="";
if ($number=~m/^[0-9]{1,}$/) {
while (length($str)>3) {
$res=' '.substr($str,length($str)-3).$res;
$str=substr($str,0,length($str)-3);
}
}
$res=$str.$res;
return $res;
}
Внутренние переменные можно использовать и вне шаблона, ссылаясь на них как на скаляры с именами $1, $2, $3, ... $n:
$text = "I have 4 apples.";
if ($text =~ /(\d+)/) {
print "Here is the number of apples: $1.\n";
}
Here is the number of apples: 4.
В следующем примере мы изменяем порядок трех слов в текстовой строке с помощью команды s/.../.../:
$text = "I see you.";
$text =~ s/^(\w+) *(\w+) *(\w+)/$3 $2 $1/;
print $text;
you see I.
В следующем примере мы последовательно заменим местами пары слов, заданных во входном тексте, оставив между ними по одному пробелу:
$text = "One Two Three Four Five Six";
$text =~ s/(\w+)\s*(\w+)/$2 $1 /g;
Two One Four Three Six Five
Следующая команда подсчитывает количество букв x в заданной строке текста:
$text = "Here is texxxxxt.";
$counter = 0;
while ($text =~ m/x/g) {
print "Found another x.\n";
$conter++;
}
Print "Total amount = $counter.\n";
Total amount = 5.
В следующем примере из текстовой строки последовательно извлекаются и выводятся пары имя/значение до тех пор,
пока строка не закончится:
$text = "X=5; z117e=3.1416; temp=1024;";
$docycle = 1; $counter = 0;
while ($docycle) {
undef $name; undef $value;
if ($text =~ m/(\w+)\s*=\s*/g) {$name = $1;}
if ($text =~ m/([\d\.\+\-]*)\s*;/g) {$value = $1;}
if (defined($name) and defined($value)) {
print "Name=$name, Value=$value.\n";
$counter++;
} else {
$docycle = 0;
}
}
print "I have found $conter values.\n";
Name=X, Value=5.
Name=z117e, Value=3.1416.
Name=temp, Value=1024.
I have found 3 values.
В следующем примере из строки последовательно извлекаются буквы p, o и q и выводится текущая позиция поиска:
$index = 0;
$_ = "ppooqppqq";
while ($index++ < 2) {
print "1: ’";
print $1 while /(o)/gc; print "’, pos=", pos, "\n";
print "2: ’";
print $1 if /\G(q)/gc; print "’, pos=", pos, "\n";
print "3: ’";
print $1 while /(p)/gc; print "’, pos=", pos, "\n";
}
1: ’oo’, pos=4
2: ’q’, pos=5
3: ’pp’, pos=7
1: ’’, pos=7
2: ’q’, pos=8
3: ’’, pos=8
В следующем фрагменте кода, заменяющем строчные буквы на заглавные:
$text = "Here is the text.";
$text =~ tr/a-z/A-Z/;
print $text;
HERE IS THE TEXT.
Для замены заглавных букв на строчные и наоборот, достаточно выполнить команду:
$text = "MS Windows 95/98/NT";
$text =~ tr/A-Za-z/a-zA_Z/;
print $text;
ms wINDOWS 95/98/nt
Удаляем строчные латинские буквы и заменяем пробелы на слеши:
$text = "Here is the text.";
$text =~ tr[ a-z][/]d;
print $text;
H///.
Заменим на звездочки все символы, кроме строчных латинских букв:
$text = "Here is the text.";
$text =~ tr/a-z/*/c;
print $text;
*ere*is*the*text*
Заменим слова, состоящие из латинских букв, на однократные символы косой черты:
$text = "Here is the text.";
$text =~ tr(A-Za-z)(/)s;
print $text;
/ / / /.
Заменить множественные пробелы и нетекстовые символы на одиночные пробелы:
$text = "Here is the text.";
$text =~ tr[\000-\040\177\377][\040]s;
print $text;
Here is the text.
Сократить удвоенные, утроенные и т.д. буквы:
$text = "Here is the texxxxxxt.";
$text =~ tr/a-zA-Z//s;
print $text;
Here is the text.
Пересчитать количество небуквенных символов:
$xcount=($text =~ tr/A-Za-z//c);
Обнулить восьмой бит символов, удалить нетекстовые символы:
$text =~ tr{\200-\377}{\000-\177};
$text =~ tr[\000-\037\177][]d;
Заменить нетекстовые и 8-ми битные символы на одиночный пробел:
$text =~ tr/\021-\176/ /cs;
Поиск отдельных слов
Чтобы выделить слово, можно использовать метасимвол \S, соответствущий символам, отличным от «пробельных»:
$text = "Now is the time.";
$text =~ /(\S+)/;
print $1;
Now
Следующий код проверяет, действительно ли введенный текст представляет собой целое значение без знака и паразитных пробелов:
$text = "333";
if ($text =~ /^\d+$/) {
print "It is a number.\n";
}
It is a number.
Вы можете потребовать, чтобы число соответствовало привычному формату. То есть, число может содержать десятичную точку,
перед которой стоит по крайней мере одна цифра и, возможно, какие-то цифры после нее:
$text = "3.1415926";
if ($text =~ /^(\d+\.\d*|\d+)$/) {
print "It is a number.\n";
}
It is a number.
$text = "-2.7182";
if ($text =~ /^([+-]*\d+(\.\d*|)$/) {
print "It is a number.\n";
}
It is a number.
С помощью метасимвола \w можно проверить, состоит ли текст только из букв, цифр и символов подчеркивания
(это те символы, которые Perl называет словными (word characters)):
$text = "abc";
if ($text =~ /^\w+$/) {
print "Only word characters found.\n";
}
Only word characters found.
Однако, если вы хотите убедиться, что текст содержит латинские буквы и не содержит цифр или символов подчеркивания,
придется использовать другой шаблон:
$text = "aBc";
if ($text =~ /^[A-Za-z]+$/) {
print "Only letter characters found.\n";
}
Only letter characters found.
С помощью модификатора g перебраются все вхождения заданного шаблона.
$text = "Name:Anne Name:Burkart Name:Claire Name:Dan";
$match = 0;
while ($text =~ /Name:\s*(\w+)/g) {
++$match;
print "Match number $match is $1.\n";
}
Match number 1 is Anne
Match number 2 is Burkart
Match number 3 is Claire
Match number 4 is Dan
Когда требуется не найти, а заменить второе или третье вхождение текста, можно использовать ту же схему,
использовав в качестве тела цикла выражение Perl, вызываемое для вычисления заменяющей строки:
$text = "Name:Anne Name:Burkart Name:Claire Name:Dan";
$match = 0;
$text =~ s/(Name:\s*(\w+))/
if (++$match == 2)
{"Name:John ($2)"}
else {$1}
/gex;
print $text;
Name:Anne Name:John (Burkart) Name:Claire Name:Dan
|
|