2.36. Групи та прив’язки¶
Шаблон може не просто сказати «цей рядок збігається» – він може розбити збіг на частини й передати кожну з них додатку за іменем. Дужки навколо частини шаблону роблять її захопленою групою; об’єкт збігу потім надає кожну групу як окремий підрядок.
2.36.1. Захоплені групи¶
Загорніть будь-яку частину шаблону в (...) щоб захопити те, що вона збіглася:
>>> import re
>>> m = re.search(r'temp (\d+) at (\d+)s', 'temp 42 at 137s ok')
>>> m.group(0)
'temp 42 at 137s'
>>> m.group(1)
'42'
>>> m.group(2)
'137'
Група 0 — це завжди весь збіг.
Групи 1, 2, … — захоплені підрядки, пронумеровані зліва направо за їх відкриваючою дужкою.
Виклик
match.group()з індексом, що перевищує номер останньої групи, викидаєIndexError.
Поширений шаблон — «збіг відомої структури, захоплення змінних частин як цілих чисел»:
def parse_temp(line):
m = re.search(r'temp (\d+) at (\d+)s', line)
if not m:
return None
return int(m.group(1)), int(m.group(2))
2.36.2. Незахоплені групи¶
Дужки також групують підвираз, щоб квантифікатор міг застосовуватися до всієї групи. Це єдина мета групування в r'(ab)+' – «один або більше ab». Той факт, що ab з’являється як група 1 — лише побічний ефект.
Щоб групувати без захоплення, використовуйте (?:...)
>>> re.search(r'(?:ab)+', 'xababy').group(0)
'abab'
Незахоплені групи підтримують нумерацію груп акуратною, коли шаблон використовує групування для структури, але не потребує виокремлювати кожну частину.
2.36.3. Прив’язки¶
Прив’язки не збігаються з символом – вони збігаються з позицією.
^– початок рядка.$– кінець рядка.
Прив’язки — це те, що змушує re.match() та re.search() поводитися по-різному. re.match(p, s) — те саме, що re.search('^' + p, s): воно примушує шаблон починатися з позиції 0. Додавання $ до кінця шаблону змушує шаблон збігатися з цілим рядком і нічим іншим:
>>> re.search(r'^\d+$', '12345')
<match num=1>
>>> re.search(r'^\d+$', '12345 ok') is None
True
^ та $ в MicroPython re завжди означають початок і кінець цілого рядка, переданого до re.search(). Немає прапора re.MULTILINE, щоб вони збігалися з кожним вбудованим символом нового рядка, і $ не збігається з позицією перед кінцевим \n – це має бути абсолютний кінець вхідних даних. Щоб отримати поведінку за рядками, спочатку розбийте вхідні дані на рядки й запустіть шаблон на кожному рядку.
2.36.4. Набори символів¶
Квадратні дужки визначають явний набір символів. Збіг споживає рівно один символ із набору.
[abc]– один зa,b,c.[a-z]– один символ у діапазоні відaдоz(включно).[a-zA-Z0-9]– літери або цифри. Три діапазони в поєднанні.[^abc]– не один зa,b,c.^заперечує лише тоді, коли він є першим символом усередині дужок.
Приклади:
>>> re.search(r'[A-F0-9]{6}', 'colour #1a2b3c rest').group(0)
'1A2B3C'
>>> re.search(r'[A-F0-9]{6}', 'colour #1a2b3c rest') is None
True
Перший виклик на практиці повертає None, бо буквальний текст написаний рядковими літерами. MicroPython re не має прапора re.IGNORECASE – щоб збігати незалежно від регістру, запишіть обидва варіанти в набір:
>>> re.search(r'[A-Fa-f0-9]{6}', 'colour #1a2b3c rest').group(0)
'1a2b3c'
Скорочення класів (\d, \s, \w та їх заперечені форми) також можна використовувати всередині [...]: [\w-] означає «символи слова або буквальне тире».
2.36.5. Жадібні й ліниві квантифікатори¶
Квантифікатори *, +, ? і {m,n} за замовчуванням є жадібними – вони збігають якомога більше символів, поки решта шаблону ще дозволяє. Часто це саме те, що потрібно; іноді – ні:
>>> re.search(r'<(.+)>', 'a <b> <c> d').group(1)
'b> <c'
Жадібний .+ захопив усе аж до останнього >. Додавання ? робить квантифікатор лінивим – він збігає якомога менше:
>>> re.search(r'<(.+?)>', 'a <b> <c> d').group(1)
'b'
Лінива форма зупиняється на першому >. Ліниві квантифікатори часто з’являються під час вилучення збалансованих роздільників із рядка.
2.36.6. Зворотні посилання при заміні¶
re.sub() може посилатися на захоплені групи в рядку заміни через \1, \2, … Заміна переписує кожен збіг, використовуючи захоплені частини:
>>> re.sub(r'(\d+)\.(\d+)', r'\2.\1', 'swap 12.34 and 5.6')
'swap 34.12 and 6.5'
Кожен збіг захоплює два числа, а заміна міняє їх місцями. \g<1> – альтернативний синтаксис для того ж самого – корисний, коли наступний символ у рядку заміни є цифрою (r'\g<1>0' щоб додати буквальний нуль до групи 1, а не читати «група 10»).
2.36.7. Що недоступне¶
Нагадування про те, що MicroPython re не підтримує, якщо шаблон із CPython потрапить сюди і вас здивує:
Lookahead
(?=...)та lookbehind(?<=...)– не реалізовані.Іменовані групи
(?P<name>...)та іменовані зворотні посилання(?P=name)– не реалізовані.Константи прапорів на кшталт
re.IGNORECASE,re.MULTILINE,re.DOTALL– не підтримуються. Самостійно побудуйте набір без урахування регістру або попередньо розбийте вхідні дані.Методи
match.groups(),match.span(),match.start()таmatch.end()залежать від рівня ROM, який жодна з поставлених плат OpenMV не вмикає. Код, що покладається на них, не запуститься на камері.
За наявності шаблонів, груп і прив’язок набір інструментів регулярних виразів на камері є достатньо малим, щоб вивчити його за одне заняття, і достатньо потужним, щоб виконати все, крім контекстно-залежного аналізу.