Regulaaravaldised

Ago video antud teemal.

Paljud erinevad ülesanded on seotud tekstist mingi seaduspärasusele vastava info leidmisega. Näiteks on ülesandeks leida ette antud tekstist kõik meiliaadressid. Regulaaravaldis on formaalne viis tekstis leiduva mustri kirja panemiseks. Mustriks võib näiteks meiliaadress või telefoninumber.

Pythonis on regulaaravaldistega töötamiseks tehtud moodul re.

Järgnevas näites otsime sõnest “an example word:cat!!!” üles alamsõne, mis vastab regulaaravaldisele word:\w\w\w. Regulaaravaldisele vastab täpne sõne “word:” ning sellele järgnevad 3 suvalist tähte.

Meetod re.search(pattern, text) tagastab otsingu õnnestumisel match objekti koos leitud alamsõnega vastasel juhul tagastatakse None.

import re text = 'an example word:cat!!' pattern = r'word:\w\w\w' match = re.search(pattern, text) # If-statement after search() tests if it succeeded if match: print('found', match.group()) ## 'found word:cat' else: print('did not find')

match = re.search(pattern, text) salvestab otsingu tulemuse muutujasse match. if match not None (ehk if match) kontrollib, kas otsing õnnestus. match.group() tagastab leitud teksti (“word:cat”).

r"string" on “raw” tüüpi string, mis tähendab, et kurakaldkriipsud("\") jäetakse teksti alles. Nii on mugavam regulaaravaldisi kirja panna, kuna regulaaravaldistes kasutatakse mustrite kirjapanemiseks kurakaldkriipse.

Näide:

raw string
r'word:\w\w\w'
regular string
'word:\\w\\w\\w'

Süntaks

Tabel annab lühiülevaate regulaaravaldise süntaksist. Täpsemalt võib vaadata näiteks siit

Muster info Näide Tekst (kust otsitakse)
      Leiab Ei leia
täht ise info “abc” “abc” “aba”
. suvaline sümbol “a.bc” “a#bc” “abc”
^ algus “^abc” “abcde” “dabc”
$ lõpp “abc$” “dabc” “abcd”
? 0 või üks kord “ab?c”

“ac”

“abc”

“abbc”
* 0 või rohkem “ab*c”

“ac”

“abc”

“abbc”

“ccbbaa”
+ 1 või rohkem “ab+c”

“abc”

“abbc”

“accbcc”

“ac”

{m} kordub m korda “ab{2}c”

“aabbcc”

“abbc”

“abc”

“abbbc”

{m, n} kordub m kuni n korda “ab+{2,3}c”

“abbcc”

“abbbcc”

“aabbbbcc”

“abc”

\

escape

Et kasutada regex erisümboleid

otseses tähenduses, näiteks,

et ”.” tähistaks punkti,

mitte suvalist tähte

“ab\.c” “ab.c” “ab#c”
[..]

sobiv hulk

hulk, millest otsida

“[ab]cd”

“acd”

“bcd”

“ccdc”

“cd”

[..-..]

sobiv vahemik

hulk, millest otsida

“[a-d]ef”

“aef”

“def”

“ef”

“abc”

[..\-] miinus hulgas “[a\-d]ef”

“def”

“-ef”

“ef-“

“cef”

(..) grupeerimine “(ab)?cd”

“cd”, “acde”

“abcde”, “abbcd”

“ab”

“abc”

| või “(ab|cd)+ef”

“abefg”, “cdefg”

“ababef”, “cdcdef”

“acef”, “efg”

“aef”, “def”

\1, \2 1., 2. sulu kattumine “(.+) \1”

“a a”, “11 12”,

“55 55”,

“aa”, “11 21”
\w tähed, numbrid, alakriips “\w+” “abc” “1a” ”.,~@”, ” “
\s tühik, tabulaator, reavahetus “a\sb” “a b” “a\tb” “ab”, “ab”
\d numbrid “\d+i” “23i” “i7”
[^..] ei kuulu hulka “[^ab]+c” “ccc”, “dec” “abc”, “bbc”

Harjutus

Regexi harjutamiseks proovi välja mõelda järgnevad mustrid:

  • Kirjuta selline email_pattern, et leida tekstist Toomase mailiaadress.
  • Kirjuta selline phone_pattern, et leida tekstist Toomase telefoninumber.
import re info_text = """ Toomas: email: akadeemia-toomas@taltech.ee phone: 5204 2456 """ email_pattern = r'' # your pattern here phone_pattern = r'' # your pattern here email_match = re.search(email_pattern, info_text) phone_match = re.search(phone_pattern, info_text) email = email_match.group() if email_match else "NOT FOUND" # -> "akadeemia-toomas@taltech.ee" phone = phone_match.group() if phone_match else "NOT FOUND" # -> "5204 2456" print(email) print(phone) import re info_text = """ Toomas: email: akadeemia-toomas@taltech.ee phone: 5204 2456 """ email_pattern = r'[\w\-]+@\w+\.\w+' phone_pattern = r'\d[\d\s]+\d' email_match = re.search(email_pattern, info_text) phone_match = re.search(phone_pattern, info_text) email = email_match.group() if email_match else "NOT FOUND" phone = phone_match.group() if phone_match else "NOT FOUND" print(email) print(phone) test_object("email") test_object("phone") success_msg("Good job!")

Grupid

Regexiga saab otsingu tulemusi gruppideks jagada. Grupide jaoks peame osa regulaaravaldisest sulgude sisse panema. Grupid on nummerdatud alates ühest. match.group(1) tagastab meile esimese grupi.

Näiteks saab kuupäevi kujul “dd.MM.yyyy” otsida tekstist järgnevalt:

import re date = "I was born on 05.12.1995." pattern = r'(\d{1,2})\.(\d{1,2})\.(\d{1,4})' match = re.search(pattern, date) print("Full match: " + match.group(0)) # or match.group() print("Day: " + match.group(1)) print("Month: " + match.group(2)) print("Year: " + match.group(3))

Mitme tulemuse leidmine

Kui tekstis on rohkem kui üks regulaaravaldisele vastav alamsõne saab kõikide vastete järjendi moodustada funktsiooniga findall()

import re text = "Minu email on foo-baz@bar.com, sõbra email on guido@baggins.com ja guits@bag.com" pattern = r'' # write email pattern here emails = re.findall(pattern, text) for email in emails: print(email) import re text = "Minu email on foo-baz@bar.com, sõbra email on guido@baggins.com ja guits@bag.com" pattern = r'[\w\-]+@\w+\.\w+' # write email pattern here emails = re.findall(pattern, text) for email in emails: print(email) test_object("emails") success_msg("Good job!")