Първото нещо, което не може да се постигне с модула string на Питон, а с регулярни изрази може, е възможността да пасват разнообразни набори от символи. Но ако това беше единствената допълнителна способност на регулярните изрази, те не биха имали голямо предимство пред модула string. Втората способност е, че можете да указвате как някои части от РИ трябва да бъдат повторени определен брой пъти.
Първият метасимвол за повторения, който ще разгледаме, е *. * не съвпада буквално със символа "*"; вместо това, той указва, че предшестващият символ трябва да се среща нула или повече пъти, вместо точно веднъж.
Например, ca*t ще пасне с "ct" (0 символа "a"), "cat"(1 "a"), "caaat" (3 символа "a"), и тъй нататък. Машината за
РИ притежава няколко вътрешни ограничения, произтичащи от размера на типа
int
в C, които ще и попречат да съчетае над 2 милиарда символа
"a". Вероятно нямате достатъчно памет, за да създадете толкова голям
символен низ, така че това ограничение едва ли ви касае.
Повторения от типа на * са лакоми. Когато повтаряте един РИ, съпоставящата машина ще се опита да ги повтори колкото се може повече пъти. Ако се окаже, че следващите части от образеца не пасват, тогава съпоставящата машина ще се върне обратно и ще опита отново, но с по-малко повторения.
Това ще се изясни с един пример, проследен стъпка по стъпка. Да разгледаме
израза a[bcd]*b. В началото той пасва с буквата "a", после
с нула или повече букви от класа [bcd]
, и накрая завършва с
"b". Сега да си представим, че съпоставяме този РИ със символния
низ "abcbd".
Стъпка | Съвпадения | Пояснение |
---|---|---|
1 | a |
a в този РИ съвпада. |
2 | abcbd |
Машината търси за съвпадения на [bcd]* отивайки колкото се може по-надалеч, т.е. в нашия случай до самия край на символния низ. |
3 | Провал | Машината проверява дали b пасва, но текущата позиция е в края на символния низ, така че съпоставянето се проваля. |
4 | abcb |
Връща се обратно назад, така че [bcd]* да пасва с един символ по-малко. |
5 | Провал | Отново опитва b, но текущата позиция е върху последния символ, който е "d". |
6 | abc |
Връща се още веднъж назад, така че [bcd]* да пасва само с "bc". |
7 | abcb |
Отново опитва b. Този път символът на текущата позиция е "b", така че съпоставянето успява. |
Сега е достигнат края на дадения РИ и той е паснал с "abcb". Това показва как в началото съпоставящата машина отива колкото се може по-далеч, и ако не се открие съвпадение, тогава тя постепенно се връща назад и отново опитва останалата част от дадения РИ. Тя ще се връща назад докато опита случая при нула повторения на [bcd]*, и ако в последствие и този опит пропадне, тя ще заключи, че символният низ изобщо не пасва с този РИ.
Друг метасимвол за повторение е +, който пасва един или повече пъти. Обърнете внимание на разликата между * и +; * пасва нула или повече пъти, така че това дето трябва да се повтаря може изобщо да не се среща, докато + изисква минимум едно срещане. За да използваме подобен пример, ca+t ще пасне с "cat" (1 символ "a"), "caaat" (3 символа "a"), но няма да пасне с "ct".
Съществуват още два квалификатора за повторение. Въпросителният знак ? пасва с едно или с нула повторения. Можете да мислите за него като за белег за нещо незадължително. Например, пиво-?варна пасва хем с "пивоварна", хем с "пиво-варна".
Най-сложният квалификатор е {m,n}, където m и n са десетични числа. Той обозначава, че трябва да има поне m на брой повторения, но най-много n. Например, a/{1,3}b ще пасне с "a/b", "a//b", и "a///b". Но няма да пасне с "ab", защото не съдържа наклонени черти, или с "a////b", защото съдържа четири.
Можете да изпуснете някоя от стойностите на m или n. В такъв случай, на нейно място се приема някаква разумна стойност. Изпускането на m се тълкува като 0 за долна граница, докато изпускането на n води до установяването на безкрайността като горна граница - в действителност, споменатото по-рано ограничение до 2 милиарда, но защо пък това да не е безкрайност...
Читателите от редукционалисткия лагер може би са забелязали, че останалите 3 квалификатора също могат да бъдат изразени чрез тази система за означаване. {0,} е същото като *, {1,} е еквивалент на +, и {0,1} е същото като ?. Но е по-добре да използвате *, +, или ?, просто защото те са по-кратки и лесни за четене.