Искаме да се уверим, че подаденият ни телефонен номер е в следния формат: [02] 5–7 цифри
С други думи:
Например, валидни номера са 02555469
, както и 987654
.
# 15-минутно
# формат: [02] 5-7 цифри
def validate_phone_str(number):
if '02' == number[:2]:
return validate_phone_str(number[2:])
if all([c.isdigit() for c in number]):
return 5 <= len(number) <= 7
return False
# шаблон, който се търси
def validate_phone_re(number):
return bool(re.search(r'^(02)?\d{5,7}$', number))
re
.import re
re.search('pattern', 'Find the pattern...')
Всичко е чудесно, но аз вече съм майстор на регулярните изрази.
За всички вас имаме следната задача:
Да се провери дали дадено число е просто чрез регулярен израз. Разрешени операции са:
re.search
с подходящ шаблон.- Употребата на низа '1'.
- Операторa
*
.
def testRun():
samples = "01234567 523456 02789a012 027890012 023456 02023456".split()
for number in samples:
print "%s %s %s" % (number.ljust(10),
str(validate_phone_str(number)).ljust(6),
validate_phone_re(number))
>>> testRun()
01234567 False False
523456 True True
02789a012 False False
027890012 True True
023456 False True
02023456 False True
Хм. Я гледай ти... Къде сбъркахме?
# Грешното ни, 15-минутно решение
def validate_phone_str(number):
if '02' == number[:2]:
return validate_phone_str(number[2:])
if all([c.isdigit() for c in number]):
return 5 <= len(number) <= 7
return False
# Едноминутното решение, работещо коректно.
def validate_phone_re(number):
return bool(re.search(r'^(02)?\d{5,7}$', number))
validate_phone_str()
.(+359|00359|02)?[0-9]{5,7}
?. | ( ) [ ] { } + \ ^ $ * ?
.\
пред специален символ го прави неспециален такъв.matcher()
— по-късно):
matcher('pat', 'Find a pattern.') # 'Find a pattern.'
matcher('#', 'What ###?') # 'What ###?'
Важат за непосредствено предхождащия ги символ/клас/група. Нека го означим с s
.
s*
означава нула или повече повторения на s
.s+
търси едно или повече повторения на s
.s?
съвпада с нула или едно повторение на s
.s{m,n}
означава между m
и n
повторения на 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...'
.
съвпада с един произволен символ^
съвпада с началото на низ (или на ред, ако се работи в MULTILINE режим.)$
съвпада с края на низ (или на ред, ако се работи в MULTILINE режим.)|
има смисъл на или, например:
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('m|c|n', 'abcdef') # 'abcdef'
matcher('(ab)|c|e', 'abcdef') # 'abcdef'
matcher('m[a-c]|c|e', 'abcdef') # 'abcdef'
[
и ]
, например [aeoui]
.>>> 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'
\d
— една цифра; същото като [0-9]
.\D
— един символ, който не е цифра; същото като [^0-9]
.\s
— един whitespace символ — [\t\r\n\f\v]
.\S
— един символ, който не е whitespace — [^\t\r\n\f\v]
.\w
— една буква или цифра.\W
— един символ, който не е буква или цифра.\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'
Групите са частите от даден шаблон, оградени в (
и )
.
Към тях можем да се обръщаме и от самия шаблон чрез специалните класове \1
— първата група,
\2
— втората и така нататък. Няколко примера:
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.'
re
re.search(pattern, string, flags=0)
re.match(pattern, string, flags=0)
re.findall(pattern, string, flags=0)
re.split(pattern, string, maxsplit=0)
re.sub(pattern, repl, string, count=0)
re.compile(pattern, flags=0)
re.I
(re.IGNORECASE) — Perform case-insensitive matching.re.L
(re.LOCALE) — Make \w, \W, \b, \B, dependent on the current locale.re.M
(re.MULTILINE) — "^" matches the beginning of lines as well as the string.re.S
(re.DOTALL) — "." matches any character at all, including the newline.re.X
(re.VERBOSE) — Ignore whitespace and comments for nicer looking RE's.re.U
(re.UNICODE) — Make \w, \W, \b, \B, dependent on the Unicode locale.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:]
help(re)