Регулярни изрази

„ Програмиране с Python“, ФМИ

24.03.2011 г.

Но преди това…

Въпроси (1)

world.py:

import re

def a(): pass
b = 42
_c = []
__d__ = {}

Кои имена ще са достъпни през модула при import world?

Въпроси (2)

import games.chess

games.chess.play()

Какво трябва да е налице за да работи този код?

Въпроси (3)

Каква е разликата между

import baba

и

from . import baba

Въпроси (4)

Какво се импортира при:

from world import *

За какво ще си говорим днес

Проблематика

Работа с низове:

Примерни проблеми — много

Това означава:
  • Трябва да съдържа само цифри
  • Може да започва с код на населеното място: `02`, `032` или `052`
  • След кода, дължината му може да е между 5 и 7 цифри
  • Самият номер (след кода) не може да започва с 0, 1, 2, 3 или 4

Вариант за решение

def validate_phone_str(number):
    if '02' == number[:2]:
        return validate_phone_str(number[2:])
    elif number[:3] in {'032', '052'}:
        return validate_phone_str(number[3:])
    if all([c.isdigit() for c in number]):
        return 5 <= len(number) <= 7
    return False

Втори вариант за решение

def validate_phone_re(number):
    pattern = r'^(02|032|052)?[5-9]\d{4,6}$'
    return bool(re.search(pattern, number))

Преди това, обещаната задачка

Да се провери дали дадено число е просто чрез един ред пайтън-код и регулярен израз. Разрешени операции са:
  • Самото число, разбира се.
  • re.search с подходящ шаблон.
  • Употребата на низа '1'.
  • Операторa *.
Решения — по-късно.

Понятия

Регулярните изрази в контекста на Пайтън

Задаване на шаблон

Нашата помощна функция matcher

Пример

>>> matcher('pat', 'Find a pattern.')
'Find a pattern.'
>>> matcher('#', 'What ###?')
'What ###?'

Магия от level 1 — Повторения (quantifiers)

Важат за непосредствено предхождащия ги символ/клас/група. Нека го означим с s.

където можем да пропуснем m или n. s{,n} има смисъл на нула до n повторения, а s{m,} — поне m повторения.`

Скоби и групиране

Символите ( и ) се използват за логическо групиране на части от шаблона с цел:

Повече за групите — след малко.

Примери

matcher('o+', 'Goooooooogle')           # 'Goooooooogle'
matcher('[hH]o+', 'Hohohoho...')        # 'Hohohoho...'
# Хм. Не искахме точно това. По-скоро:
matcher('([hH]o)+', 'Hohohoho...')      # 'Hohohoho...'
matcher('([hH]o){2,3}', 'Hohohoho...')  # 'Hohohoho...'

По подразбиране — алчно търсене за съвпадение (greedy). Деактивира се с `?` след квантора.

matcher('[hH]o+', 'Hoooooohohooo...')   # 'Hoooooohohooo...'
matcher('[hH]o+?', 'Hoooooohohooo...')  # 'Hoooooohohooo...'

Значения на специалните символи

matcher('day|nice', 'A nice dance-day.')   # 'A nice dance-day.'
matcher('da(y|n)ce', 'A nice dance-day.')  # 'A nice dance-day.' 

NB! Единствено | се прилага не над непосредствените му символи/класове, а на целия низ отляво/отдясно:

matcher('ab|c|e', 'abcdef')     # 'abcdef'
matcher('am|c|e', 'abcdef')     # 'abcdef'
matcher('a(m)|c|e', 'abcdef')   # 'abcdef'

Магия от level 2 (DRY) — Символни класове

>>> matcher('[aeoui]', 'Google')
'Google'
matcher('[^CBL][aeoui]', 'Cobol')  # 'Cobol'
>>> matcher('[0-9]{1,3}-[a-z]', 'Figure 42-b')
'Figure 42-b'
>>> matcher('[^a-zA-Z-]', 'Figure-42-b')
'Figure-42-b'

Предефинирани класове

Примери за употреба на класове

matcher(r'\d+', 'Phone number: 5551234')
# 'Phone number: 5551234'
matcher(r'\w+', 'Phone number: 5551234')
# 'Phone number: 5551234'
matcher(r'\s+', 'Phone number: 5551234') 
# 'Phone number: 5551234' 

Gandalf The Gray — Групи

matcher(r'(\w+).*\1', 'Matches str if str repeats one of its words.');
'Matches str if str repeats one of its words.'
 
# Хм. Не точно. Нека опитаме пак:
matcher(r'(\b\w+\b).*\1', 'Matches str if str repeats one of its words.');
'Matches str if str repeats one of its words.'

Групи за напреднали (Gandalf The White)

Методи на модула re

Методи на модула re (2)

MatchObject

Флагове

Кодът на matcher()

def matcher(regex, string):
    match = re.search(regex, string)
    if match is None: return string
    start, end = match.span()
    return string[:start] 
           + '<<<' + string[start:end] + '>>>' + 
           string[end:]

На финалната права…

Още въпроси?

XKCD