perlrequick - Perl regular expressions quick start

НАИМЕНОВАНИЕ

perlrequick - Perl regular expressions бърз старт


ОПИСАНИЕ

Тази страница обхваща най-основните неща по създаването и използването на regular expressions ('regexes') в Perl.


Ръководството

Просто съвпадение на думи

Най-простата regex е само дума или, общо казано, низ от символи. Regex, състояща се от дума, дава съвпадение с всеки низ, който съдържа тази дума:

    "Hello World" =~ /World/;  # съвпадение

В този израз, World е regex и //, ограждащи /World/ казват на perl да претърси низ за съвпадение. Операторът =~ асоциира низът с regex съвпадението и дава за резултат true ако има съвпадение и false ако не съвпада. В нашият случай, World съвпада с втората дума в "Hello World", така че резултатът от сравнението е true. Тази идея има няколко вариации.

Изрази като този са полезни в условни преходи:

    print "It matches\n" if "Hello World" =~ /World/;

Начинът на съвпадение може да бъде променен, използвайки операторът !~

    print "It doesn't match\n" if "Hello World" !~ /World/;

Символният низ в regex може да бъде заменен от променлива:

    $greeting = "World";
    print "It matches\n" if "Hello World" =~ /$greeting/;

Ако търсите съвпадение в $_, частта $_ =~ може да бъде махната:

    $_ = "Hello World";
    print "It matches\n" if /World/;

И на края, разделителите // за съвпадение могат да бъдат сменени с произволни, слагайки 'm' отпред:

    "Hello World" =~ m!World!;   # Съвпада, разделено с '!'
    "Hello World" =~ m{World};   # съвпада, обърнете внимание на '{}'
    "/usr/bin/perl" =~ m"/perl"; # съвпада след '/usr/bin',
                                 # '/' става обикновен символ

Regexes трябва да намери абсолютно точно съвпадение в низа, за да може резултатът да е true:

    "Hello World" =~ /world/;  # Не съвпада, разлика в главни и малки букви
    "Hello World" =~ /o W/;    # съвпада, ' ' е обикновен символ
    "Hello World" =~ /World /; # не съвпада, няма ' ' в края.

perl винаги връща резултатът от първото намерено съвпадение в низът:

    "Hello World" =~ /o/;       # съвпада с 'o' в 'Hello'
    "That hat is red" =~ /hat/; # съвпада с 'hat' в 'That'

Не всички символи могат да бъдат използвани 'както са' в съвпадението. Някои символи, наричани метасимволи, са запазени да употреба в regex нотации. Метасимволите са

    {}[]()^$.|*+?\

Метасимвол може да бъде използван за съвпадение, слагайки отпред обратно наклонена черта:

    "2+2=4" =~ /2+2/;    # не съвпада, + е метасимвол
    "2+2=4" =~ /2\+2/;   # съвпада, \+ се възприема като обикновен +
    'C:\WIN32' =~ /C:\\WIN/;                       # съвпада
    "/usr/bin/perl" =~ /\/usr\/local\/bin\/perl/;  # съвпада

В последната regex, дробната черта '/' също е предходена от обратно наклонена, защото се използва като разделител в regex.

Непечатимите ASCII символи се представят чрез escape последователности. Общ пример са \t за tab, \n за нов ред и \r за връщане на каретата. Произволни байтове се представят чрез осмични escape последователности, например \033 или шестнайсетични escape последователности като \x1B:

    "1000\t2000" =~ m(0\t2)        # съвпада
    "cat"        =~ /\143\x61\x74/ # съвпада, но е странен начин да напишеш cat

Regex се възприемат главно като низове, оградени с двойни кавички, така че замяната с променливи също работи:

    $foo = 'house';
    'cathouse' =~ /cat$foo/;   # съвпада
    'housecat' =~ /${foo}cat/; # съвпада

С всички примери до тук, ако regex намери където и да е съвпадение, тя го приема за намерено. За да конкретизирате къде точно да го търси трябва да използвате anchor метасимволите ^ и $. ^ означава съвпадение в началото на низа, а $ означава съвпадение в края на низа или преди нов ред в края на низа. Някои примери:

    "housekeeper" =~ /keeper/;         # съвпада
    "housekeeper" =~ /^keeper/;        # не съвпада
    "housekeeper" =~ /keeper$/;        # съвпада
    "housekeeper\n" =~ /keeper$/;      # съвпада
    "housekeeper" =~ /^housekeeper$/;  # съвпада

Използване на символни класове

Символният клас позволява търсене на съвпадение на област от възможни символи вместо единичен символ, в определена позиция. Символните класове са отделени със скоби [...] набор от символи, които да бъдат използвани за съвпадение. Ето някои примери:

    /cat/;            # съвпада с 'cat'
    /[bcr]at/;        # съвпада с 'bat', 'cat', или 'rat'
    "abc" =~ /[cab]/; # съвпада с 'a'

В последният израз, въпреки че 'c' е първият символ в класа, първата позиция, където regex открива съвпадение е 'a'.

    /[yY][eE][sS]/; # съвпада с 'yes' без значение от главни и малки букви
                    # 'yes', 'Yes', 'YES', и т.н.
    /yes/i;         # също съвпада с 'yes', без значение от главни и малки букви

Последният пример показва съвпадение с използването на 'i' модификаторът, който прави търсенето независимо от главни и малки букви.

Символните класове имат също обикновени и специални символи, но наборът от тях в символният клас е различен от този, извън него. Специалните символи за символните класове са -]\^$ и се използват с escape преди тях:

   /[\]c]def/; # намира ']def' или 'cdef'
   $x = 'bcr';
   /[$x]at/;   # съвпада с 'bat, 'cat', или 'rat'
   /[\$x]at/;  # съвпада с '$at' или 'xat'
   /[\\$x]at/; # съвпада с '\at', 'bat, 'cat', или 'rat'

Специалният символ '-' действа като оператор за обхват в символните класове, за да може неудобните [0123456789] и [abc...xyz] да станат по-ясните [0-9] и [a-z]:

    /item[0-9]/;  # намира 'item0' или ... или 'item9'
    /[0-9a-fA-F]/;  # намира шестнайсетична цифра

Ако '-' е първият или последният символ в символен клас, той се възприема като обикновен символ.

Специалният символ ^ в началото на символен клас става отрицателен символен клас, който намира съвпадение с всички останали символи, но не и тези, които са в скобите. И двете [...] и [^...] трябва да намерят съвпадение, иначе се връща резултат false. От тук

    /[^a]at/;  # не съвпада с 'aat' или 'at', но съвпада с
               # всички други като 'bat', 'cat, '0at', '%at', и т.н.
    /[^0-9]/;  # съвпада с нечислов символ
    /[a^]at/;  # съвпада с 'aat' или '^at'; тук '^' е обикновен

Perl има някои съкращения за стандартни символни класове:

* \d е цифра и замества [0-9]
* \s е празен символ и замества [\ \t\r\n\f]
* \w е буквен символ (буквено-цифрен или _) и замества [0-9a-zA-Z_]
* \D е обратното на \d; то замества всеки символ освен цифра [^0-9]
* \S е обратното на \s; всеки не празен символ [^\s]
* \W е обратното на \w; то замества всеки не-буквен символ [^\w]
* Точка '.' съвпада с всеки символ освен "\n"

Съкращенията \d\s\w\D\S\W могат да се използват и в символните класове и извън тях. Ето някои примери в действие:
    /\d\d:\d\d:\d\d/; # съвпада с формат за час hh:mm:ss
    /[\d\s]/;         # съвпада с всяка цифра или празен символ
    /\w\W\w/;         # съвпада с буквен символ, следван от не-буква,
                      # следвана от друга буква
    /..rt/;           # съвпада с каквито и да са два символа, следвани от 'rt'
    /end\./;          # съвпада с 'end.'
    /end[.]/;         # същото, съвпада с 'end.'

word anchor \b съвпада с границата между буквен и не-буквен символ. \w\W или \W\w:

    $x = "Housecat catenates house and cat";
    $x =~ /\bcat/;  # съвпада с cat в 'catenates'
    $x =~ /cat\b/;  # съвпада с cat в 'housecat'
    $x =~ /\bcat\b/;  # съвпада с 'cat' в края на низа

В последният пример, краят на низа се приема за граница между думи.

Съвпадение на това или онова

Можем да търсим съвпадения с различни символни низове с метасимволът за алтернатива '|'. За да намерим съпвадение с dog или cat, ние оформяме regex dog|cat. Както и преди, perl ще се опита да намери първото възможно съвпадение с regex. За всеки символ поотделно, perl ще опита да намери първата алтернатива, dog. Ако dog не съвпада, perl ще опита следващата алтернатива, cat. Ако и cat не съвпада, тогава съвпадението пропада и perl отива на следващата позиция в низа. Някои примери:

    "cats and dogs" =~ /cat|dog|bird/;  # съвпада с "cat"
    "cats and dogs" =~ /dog|cat|bird/;  # съвпада с "cat"

Въпреки, че dog е първата алтернатива във втората regex, cat се среща първа в низа.

    "cats"          =~ /c|ca|cat|cats/; # съвпада с "c"
    "cats"          =~ /cats|cat|ca|c/; # съвпада с "cats"

При дадена позиция на символа, първата алтернатива, която позволява на regex съвпадението да открие съответствие, ще бъде тази която съвпада. По-горе, всички алтернативи търсят съвпадение в първата позиция на низа, така че първата съвпада.

Групиране на нещата и йерархично съвпадение

Метасимволите за групиране () позволяват на част от regex да бъде възприемана като самостоятелен блок. Частите от regex се групират, като се ограждат със скоби. Regex house(cat|keeper) означава съвпадение на house, последвано от cat или keeper. Ето още няколко примера:

    /(a|b)b/;    # съвпада с 'ab' или 'bb'
    /(^a|b)c/;   # съвпада с 'ac' в началото на низа или 'bc' където и да е

    /house(cat|)/;  # съвпада или с 'housecat' или с 'house'
    /house(cat(s|)|)/;  # съвпада или с  'housecats' или с 'housecat' или с
                        # 'house'.  Както виждате, групите могат да бъдат вмъквани една в друга

    "20" =~ /(19|20|)\d\d/;  # съвпада с null алтернативата '()\d\d',
                             # понеже '20\d\d' не може да съвпадне

Отделяне чрез съвпадения

Метасимволите за групиране () позволяват също и отделяне на части от низа, които съвпадат. За всяка група, частта която съвпада се предава на специални променливи $1, $2 и т.н. Те могат да се използват както всички обикновени променливи:

    # Отделя часове, минути, секунди
    $time =~ /(\d\d):(\d\d):(\d\d)/;  # съвпада с форматът hh:mm:ss
    $hours = $1;
    $minutes = $2;
    $seconds = $3;

В списък, съвпадението /regex/ с групиране ще върне списък от съвпадащи стойности ($1,$2,...). Така че можем да го пренапишем като

    ($hours, $minutes, $second) = ($time =~ /(\d\d):(\d\d):(\d\d)/);

Ако има няколко, вмъкнати една в друга групи с regex, $1 получава групата с най-левите отварящи скоби, $2 получава следващата група и т.н. Ето например сложна regex и под нея съвпадащите променливи:

    /(ab(cd|ef)((gi)|j))/;
     1  2      34

Асоциирани със съвпадащите променливи $1, $2, ... са backreferences \1, \2, ... Backreferences са променливи за съвпадение, които могат да бъдат използвани вътре в regex:

    /(\w\w\w)\s\1/; # намира последователности като 'the the' в низа

$1, $2, ... трябва да бъдат използвани само извън regex, a \1, \2, ... само вътре в regex.

Повтарящи се съвпадения

Количествените метасимволи ?, *, +, и {} ни позволяват да определим броя на повторенията на частта от regex, която приемаме за съвпадение. Те се слагат непосредствено след символът, символният клас, или група, които искаме да укажем. Имат следните значения:

Ето някои примери:

    /[a-z]+\s+\d*/;  # съвпада с дума с малки букви, поне няоколко интервала и
                     # произволен брой цифри
    /(\w+)\s+\1/;    # съпада с повтарящи се думи с произволна дължина
    $year =~ /\d{2,4}/;  # проверява дали годината е с размер поне 2 знака, но не повече
                         # от 4 знака
    $year =~ /\d{4}|\d{2}/;    # по-добро съвпадение; отхвърля години с 3 знака

Тези количествени указатели ще опитат да намерят колкото са възможни съвпадения в низът, докато все още има възможност regex да съвпада. Така че, имаме:

    $x = 'the cat in the hat';
    $x =~ /^(.*)(at)(.*)$/; # съвпада,
                            # $1 = 'the cat in the h'
                            # $2 = 'at'
                            # $3 = ''   (0 съвпадения)

Първият указател .* взема максимално възможното от низът, докато regex съвпада. За вторият указател .* няма останала част от низа, така че съвпада 0 пъти.

Повече съвпадения

Има още няоколко неща, които може би искате да научите относно операторите за съвпадение. В кодът

    $pattern = 'Seuss';
    while (<>) {
        print if /$pattern/;
    }

perl трябва да преизчислява $pattern всеки път, минавайки през цикълът. Ако $pattern няма да се променя, за да се извърши само веднъж присвояването, използвайте модификаторът //o. Ако не желаете никакви присвоявания изобщо, използвайте специалният разделител m'':

    $pattern = 'Seuss';
    m'$pattern'; # съвпада с '$pattern', не 'Seuss'

Глобалният модификатор //g позволява на операторите да търсят съпвадения из низа колкото е възможно пъти. В скаларни променливи, успешното съвпадение в низът ще кара //g да преминава от съвпадение на съвпадение, като се пази всяка позиция, където е намерено съвпадение. Позицията можете да вземете или да установите чрез функцията pos(). За пример,

    $x = "cat dog house"; # 3 думи
    while ($x =~ /(\w+)/g) {
        print "Word is $1, ends at position ", pos $x, "\n";
    }

извежда

    Word is cat, ends at position 3
    Word is dog, ends at position 7
    Word is house, ends at position 13

Неуспешно съвпадение или промяна на низа в който се търси, нулира позицията. Ако не искате това да става след всяко неуспешно , добавете //c, както е в /regex/gc.

В списък, //g връща списък от съвпадащи групи или, ако няма такива, списък от съвпадения за цялата regex. От тук

    @words = ($x =~ /(\w+)/g);  # съвпада
                                # $word[0] = 'cat'
                                # $word[1] = 'dog'
                                # $word[2] = 'house'

Търсене и замяна

Търсене и замяна се извършва чрез s/regex/замяна/модификатори. Замяната е Perl низ, възприеман като ограден с двойни кавички, който заменя в низът това, което regex открива като съвпадение. Perl double quoted string that replaces in the string whatever is matched with the regex. Операторът =~ се използва и за асоцииране на низ със s///. Ако се извършва действие с $_, $_ =~ може да не се вписва. Ако има открито съвпадение, s/// връща броя на извършените замяни, а в противен случай връща false. Ето няколко примера:

    $x = "Time to feed the cat!";
    $x =~ s/cat/hacker/;   # $x съдържа "Time to feed the hacker!"
    $y = "'quoted words'";
    $y =~ s/^'(.*)'$/$1/;  # маха единичните кавички (апострофите),
                           # $y съдържа "quoted words"

С операторът s///, променливите от съвпадението $1, $2, и т.н. са достъпни веднага, за да се използват като израз за замяна. С глобалният модификатор s///g ще се извърши търсене и замяна на всички срещания на regex в низът:

    $x = "I batted 4 for 4";
    $x =~ s/4/four/;   # $x съдържа "I batted four for 4"
    $x = "I batted 4 for 4";
    $x =~ s/4/four/g;  # $x съдържа "I batted four for four"

Модификаторът за изчисление s///e изпълнява eval{...} в низът за замяна и изчисленият резултат се използва за действителната замяната. Някои примери:

    # обръщане на всички думи в низ
    $x = "the cat in the hat";
    $x =~ s/(\w+)/reverse $1/ge;   # $x съдържа "eht tac ni eht tah"

    # превръща проценти в десетичен вид
    $x = "A 39% hit rate";
    $x =~ s!(\d+)%!$1/100!e;       # $x съдържа "A 0.39 hit rate"

В последният пример се вижда, че s/// може да използва и други разделители, като s!!! и s{}{}, а даже и s{}//. Ако се използват единични кавички (апострофи) s''', тогава regex търсенето и замяната ще се възприемат като низове, оградени с единични кавички (апострофи).

Операторът split

split /regex/, string разделя string на списък от поднизове и го връща като резултат. Regex определя символната последователност, на която ще бъде разделен низът string. Например, за да разделим низ на отделни думи, можем да използваме

    $x = "Calvin and Hobbes";
    @word = split /\s+/, $x;  # $word[0] = 'Calvin'
                              # $word[1] = 'and'
                              # $word[2] = 'Hobbes'

За да разделим списък от числа, разделен със запетаи, използваме

    $x = "1.618,2.718,   3.142";
    @const = split /,\s*/, $x;  # $const[0] = '1.618'
                                # $const[1] = '2.718'
                                # $const[2] = '3.142'

Ако се ползва празна regex //, то низът се разделя на отделни символи. Ако regex съдържа групиране, тогава полученият списъкъ също ще съдържа съвпадащите поднизове от групите.

    $x = "/usr/bin";
    @parts = split m!(/)!, $x;  # $parts[0] = ''
                                # $parts[1] = '/'
                                # $parts[2] = 'usr'
                                # $parts[3] = '/'
                                # $parts[4] = 'bin'

Понеже първият символ от $x съвпада с regex, split добавя празен първоначален елемент към списъкът.


БЪГОВЕ

Няма.


ВИЖ СЪЩО И

This is just a quick start guide. For a more in-depth tutorial on regexes, see perlretut and for the reference page, see perlre.


AUTHOR AND COPYRIGHT

Copyright (c) 2000 Mark Kvale All rights reserved.

This document may be distributed under the same terms as Perl itself.

Този документът е преведен от Николай Цветков.

Acknowledgments

The author would like to thank Mark-Jason Dominus, Tom Christiansen, Ilya Zakharevich, Brad Hughes, and Mike Giroux for all their helpful comments.