- Simvol sinifləri, kəmiyyət göstəriciləri və lövbərlərlə şablon yazmaq
- Qruplar və adlı qruplarla mətndən hissələr çıxarmaq
- Acgöz və tənbəl kəmiyyət göstəricilərini fərqləndirmək
re.sub,re.split, bayraqlar vəre.compileilə mətni emal etmək
Uzun mətndə bütün telefon nömrələrini tap, e-poçt ünvanının düzgün görünüb-görünmədiyini yoxla, bir milyon sətirlik log faylından tarixləri və xəta səviyyələrini çıxar. find() və split() ilə hər tapşırıq bir səhifəlik kövrək kod tələb edir. Requlyar ifadə (regex) axtardığın mətnin formasını bir qısa şablonla təsvir edir, axtarışı isə re modulu görür. Requlyar ifadələr hər yerdə işlədilir: mətn redaktorlarında, verilənlər bazalarında, əmr sətri alətlərində və saytlardakı formaların yoxlanmasında.
İlk addımlar: search, findall və xam sətirlər
Şablon kiçik xüsusi dildə yazılmış sətirdir. re.search(pattern, text) mətnin istənilən yerində birinci uyğunluğu tapır və Match obyekti (və ya None) qaytarır; .group() tapılan mətni verir. re.findall isə bütün uyğunluqların siyahısını qaytarır. \d «rəqəm», + isə «bir və ya daha çox» deməkdir:
import re
text = 'Order 17 shipped on 2026-09-15, order 245 on 2026-09-20.'
print(re.search(r'\d+', text))
print(re.search(r'\d+', text).group())
print(re.findall(r'\d+', text))
print(re.findall(r'\d{4}-\d{2}-\d{2}', text))
print(re.search(r'cancelled', text))▸ Gözlənilən nəticə
<re.Match object; span=(6, 8), match='17'> 17 ['17', '2026', '09', '15', '245', '2026', '09', '20'] ['2026-09-15', '2026-09-20'] None
Şablonların dili
| Simvol | Mənası | Nümunə |
|---|---|---|
. | yeni sətir simvolundan başqa istənilən simvol | a.c → abc, a-c |
\d, \w, \s | rəqəm, söz simvolu (hərf, rəqəm, _), boşluq simvolu | \d\d → 42 |
\D, \W, \S | əksi: rəqəm deyil, söz simvolu deyil, boşluq deyil | \S+ → 2026-09-15 |
[abc], [a-z], [^0-9] | çoxluqdan / aralıqdan bir simvol, çoxluqda olmayan simvol | [aeiou] → e |
*, +, ? | 0 və ya çox, 1 və ya çox, 0 və ya 1 | colou?r → color, colour |
{n}, {n,m} | düz n dəfə, n-dən m-ə qədər təkrar | \d{4} → 2026 |
^, $, \b | sətrin əvvəli, sonu, söz sərhədi | ^\d+$ |
a|b, (...) | alternativ, qrup | (cat|dog)s |
\., \(, \+ | xüsusi simvolun özü: nöqtə, mötərizə, üstəgəl | \+994 |
import re
print(re.findall(r'\w+', 'Salam, dünya! Привет, мир!'))
print(re.findall(r'\b\w{4}\b', 'Baku is a large city by the sea'))
print(re.findall(r'colou?r', 'color or colour?'))
print(re.findall(r'[A-Z]\w*', 'Aysel and Murad met Leyla'))▸ Gözlənilən nəticə
['Salam', 'dünya', 'Привет', 'мир'] ['Baku', 'city'] ['color', 'colour'] ['Aysel', 'Murad', 'Leyla']
Python 3-də \w Unicode-u başa düşür: istənilən əlifbanın hərflərinə uyğun gəlir, ona görə ə, ü hərfli və kiril sözlər də tapılır. \b söz simvolu ilə qeyri-söz simvolu arasındakı görünməz sərhədə uyğun gəlir, buna görə \b\w{4}\b uzun sözlərin hissələrini yox, məhz dörd hərfli bütöv sözləri tapır.
Qruplar və adlı qruplar
Mötərizələr qrup yaradır — uyğunluğun həqiqətən lazım olan hissəsini. m.group(n) n-ci qrupu qaytarır (0 nömrəli qrup bütün uyğunluqdur), m.groups() isə hamısını kortej kimi verir. Nömrələnmiş qruplar tez çaşdırır, ona görə onlara (?P<name>...) ilə ad ver və m['name'] kimi və ya hamısını birdən m.groupdict() ilə oxu. re.match yalnız sətrin əvvəlindən yoxlayır — bir log sətri üçün tam uyğundur:
import re
line = '2026-09-15 14:02:11 ERROR [payment] card declined'
m = re.match(r'(\S+) (\S+) (\w+) \[(\w+)\] (.*)', line)
print(m.group(3), '|', m.group(5))
print(m.groups())
named = r'(?P<date>\S+) (?P<time>\S+) (?P<level>\w+) \[(?P<module>\w+)\] (?P<msg>.*)'
m = re.match(named, line)
print(m['level'], m['module'])
print(m.groupdict())▸ Gözlənilən nəticə
ERROR | card declined
('2026-09-15', '14:02:11', 'ERROR', 'payment', 'card declined')
ERROR payment
{'date': '2026-09-15', 'time': '14:02:11', 'level': 'ERROR', 'module': 'payment', 'msg': 'card declined'}Şablonda qruplar varsa, findall bütün uyğunluğu yox, qrupları qaytarır — qrup bir neçədirsə, kortej şəklində. Mövqelər və ya adlı qruplar da lazımdırsa, Match obyektlərini tənbəlcə verən **finditer** ilə dövr qur:
import re
phones = 'Aysel: +994 50 123 45 67, Murad: +994 55 765 43 21'
print(re.findall(r'\+994 (\d{2}) (\d{3} \d{2} \d{2})', phones))
for m in re.finditer(r'(?P<name>\w+): (?P<phone>\+994[\d ]+\d)', phones):
print(m['name'], '->', m['phone'], m.span())▸ Gözlənilən nəticə
[('50', '123 45 67'), ('55', '765 43 21')]
Aysel -> +994 50 123 45 67 (0, 24)
Murad -> +994 55 765 43 21 (26, 50)Acgöz və tənbəl kəmiyyət göstəriciləri
Kəmiyyət göstəriciləri susmaya görə acgözdür (greedy): .+ mümkün qədər çox mətn tutur və simvolları yalnız şablonun qalan hissəsi uyğun gəlmədikdə geri verir. Sonuna ? əlavə etsən, göstərici tənbəl olur (.+?, *?, ??): mümkün qədər az götürür. \1 geri istinaddır — 1-ci qrupla eyni mətnə uyğun gəlməlidir, ona görə bağlayan teq açan teqə uyğun gəlməlidir:
import re
html = '<b>bold</b> and <i>italic</i>'
print(re.findall(r'<.+>', html))
print(re.findall(r'<.+?>', html))
print(re.findall(r'<(\w+)>(.*?)</\1>', html))▸ Gözlənilən nəticə
['<b>bold</b> and <i>italic</i>']
['<b>', '</b>', '<i>', '</i>']
[('b', 'bold'), ('i', 'italic')]Əvəzetmə, bölmə, bayraqlar və compile
re.sub(pattern, replacement, text) bütün uyğunluqları əvəz edir. Əvəzedici sətirdə \1, \2… qrupları yerləşdirir; sətir əvəzinə Match obyektini alıb yeni mətni qaytaran funksiya da vermək olar. re.split mətni şablona görə bölür, məsələn, vergül, nöqtəli vergül və boşluqların istənilən qarışığına görə:
import re
text = 'Call 050-123-45-67 or 055-765-43-21 today'
print(re.sub(r'\d{3}-\d{3}-\d{2}-\d{2}', '[hidden]', text))
print(re.sub(r'(\d{3})-(\d{3})-(\d{2})-(\d{2})', r'(\1) \2 \3 \4', text))
print(re.sub(r'\d+', lambda m: str(int(m.group()) * 2), 'a1 b22 c333'))
print(re.split(r'[,;\s]+', 'tea, coffee; juice water'))▸ Gözlənilən nəticə
Call [hidden] or [hidden] today Call (050) 123 45 67 or (055) 765 43 21 today a2 b44 c666 ['tea', 'coffee', 'juice', 'water']
Bayraqlar şablonun işini dəyişir: re.IGNORECASE (re.I) hərflərin böyük-kiçikliyinə baxmır, re.MULTILINE (re.M) ^ və $-ı hər sətrin əvvəli və sonu edir, re.DOTALL (re.S) .-yə yeni sətir simvolunu da tutmağa icazə verir, re.VERBOSE (re.X) isə şablonun içində boşluqlara və # şərhlərinə imkan yaradır. Dəfələrlə işlədilən şablonu re.compile ilə bir dəfə kompilyasiya etmək olar:
import re
EMAIL = re.compile(r'''
[\w.+-]+ # user name
@
[\w-]+(\.[\w-]+)+ # domain with at least one dot
''', re.VERBOSE)
for address in ['leyla@mail.az', 'elvin.m@edu.gov.az', 'wrong@site', 'no at.com']:
print(f'{address:20} {bool(EMAIL.fullmatch(address))}')
log = 'ERROR one\ninfo two\nError three'
print(re.findall(r'^error.*$', log, re.IGNORECASE | re.MULTILINE))▸ Gözlənilən nəticə
leyla@mail.az True elvin.m@edu.gov.az True wrong@site False no at.com False ['ERROR one', 'Error three']
re.match— yalnız sətrin əvvəlində yoxlayır.re.search— istənilən yerdə birinci uyğunluğu tapır.re.fullmatch— bütün sətir şablona uyğun gəlməlidir.re.findall/re.finditer— bütün uyğunluqlar (siyahı / Match obyektlərinin iteratoru).re.sub,re.split— əvəz etmək və bölmək.
Qeydiyyat formasında telefon düz +994 50 123 45 67 formatında yazılmalıdır: ölkə kodu, iki rəqəmli operator kodu və 3 + 2 + 2 rəqəm, aralarında bir boşluq. +994 501234567 və +994 50 123 45 67 ext rədd edilməlidir. Şablonu qur.
Həllini göstərHəllini gizlət
+ xüsusi simvoldur, ona görə \+994 yazılır.Operator kodu
\d{2}, qalan hissələr \d{3}, \d{2}, \d{2}-dir; aralarında düz bir boşluq var.Şablon:
r'\+994 \d{2} \d{3} \d{2} \d{2}'.re.fullmatch bütün sətrin uyğun gəlməsini tələb edir, ona görə sonundakı ext nömrəni etibarsız edir.Mətndəki DD.MM.YYYY formatlı bütün tarixlərin siyahısını çap et, sonra hər tarixi YYYY-MM-DD formatına çevirib mətni yenidən çap et.
import re
text = 'Exams: 15.06.2026 (math), 18.06.2026 (physics), 22.06.2026 (history).'
# 1) print the list of all dates DD.MM.YYYY
# 2) print the text with every date rewritten as YYYY-MM-DD▸ Gözlənilən nəticə
['15.06.2026', '18.06.2026', '22.06.2026'] Exams: 2026-06-15 (math), 2026-06-18 (physics), 2026-06-22 (history).
key = value sətirlərindən (bərabərlik işarəsinin ətrafında boşluq ola da, olmaya da bilər) {açar: qiymət} lüğəti qur və çap et. # ilə başlayan şərh sətirləri nəzərə alınmamalıdır.
import re
config = 'host = localhost\nport=8080\n# comment\ndebug = true'
# build a dict {key: value} from the 'key = value' lines and print it▸ Gözlənilən nəticə
{'host': 'localhost', 'port': '8080', 'debug': 'true'}Əsas fikirlər
- Şablonları xam sətir
r'...'kimi yaz;searchbirinci,findallbütün uyğunluqları tapır,fullmatchisə bütün sətri yoxlayır. - Şablonlar
\d \w \s,[...]sinifləri,* + ? {n,m}kəmiyyət göstəriciləri və^ $ \blövbərlərindən qurulur. - Qruplar
(...)və adlı qruplar(?P<name>...)hissələri çıxarır:m.group(1),m['name'],m.groupdict(). - Kəmiyyət göstəriciləri acgözdür; tənbəl axtarış üçün
?əlavə et (.+?). re.sub\1geri istinadlarını və funksiyaları qəbul edir;re.I,re.M,re.S,re.Xbayraqları axtarışı dəyişir.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
r'\d+' kimi xam sətirlə yazırıq?