ээдд. Прохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен. Николай Прохоренок Владимир Дронов
Скачать 7.92 Mb.
|
>>> r = p.search(email) >>> r.group("name") # Название ящика 'test' >>> r.group("host") # Домен 'mail.ru' Чтобы внутри шаблона обратиться к именованным фрагментам, используется следующий синтаксис: (?P=name) . Для примера получим текст между одинаковыми парными тегами: >>> s = "Text1Text2Text3" >>> p = re.compile(r"<(?P >>> p.findall(s) [('b', 'Text1'), ('I', 'Text3')] Кроме того, внутри круглых скобок могут быть расположены следующие конструкции: (?#...) — комментарий. Текст внутри круглых скобок игнорируется; (?=...) — положительный просмотр вперед. Выведем все слова, после которых распо- ложена запятая: >>> s = "text1, text2, text3 text4" >>> p = re.compile(r"\w+(?=[,])", re.S | re.I) >>> p.findall(s) ['text1', 'text2'] (?!...) — отрицательный просмотр вперед. Выведем все слова, после которых нет запятой: >>> s = "text1, text2, text3 text4" >>> p = re.compile(r"[a-z]+[0-9](?![,])", re.S | re.I) >>> p.findall(s) ['text3', 'text4'] (?<=...) — положительный просмотр назад. Выведем все слова, перед которыми распо- ложена запятая с пробелом: >>> s = "text1, text2, text3 text4" >>> p = re.compile(r"(?<=[,][ ])[a-z]+[0-9]", re.S | re.I) >>> p.findall(s) ['text2', 'text3'] (? — отрицательный просмотр назад. Выведем все слова, перед которыми распо- ложен пробел, но перед пробелом нет запятой: >>> s = "text1, text2, text3 text4" >>> p = re.compile(r"(? >>> p.findall(s) ['text4'] (?(id или name)шаблон1|шаблон2) — если группа с номером или названием найдена, то должно выполняться условие из параметра шаблон1 , в противном случае должно выпол- 130 Часть I. Основы языка Python няться условие из параметра шаблон2 . Выведем все слова, которые расположены внутри апострофов. Если перед словом нет апострофа, то в конце слова должна быть запятая: >>> s = "text1 'text2' 'text3 text4, text5" >>> p = re.compile(r"(')?([a-z]+[0-9])(?(1)'|,)", re.S | re.I) >>> p.findall(s) [("'", 'text2'), ('', 'text4')] (?aiLmsux) — позволяет установить опции регулярного выражения. Буквы a , i , L , m , s , u и x имеют такое же назначение, что и одноименные модификаторы в функции compile() В НИМАНИЕ ! Начиная с Python 3.6, опции, задаваемые внутри регулярного выражения в круглых скобках, объявлены устаревшими и не рекомендованными к использованию. В будущих версиях Python их поддержка будет удалена. Рассмотрим небольшой пример. Предположим, необходимо получить все слова, располо- женные после дефиса, причем перед дефисом и после слов должны следовать пробельные символы: >>> s = "-word1 -word2 -word3 -word4 -word5" >>> re.findall(r"\s\-([a-z0-9]+)\s", s, re.S | re.I) ['word2', 'word4'] Как видно из примера, мы получили только два слова вместо пяти. Первое и последнее сло- ва не попали в результат, т. к. расположены в начале и в конце строки. Чтобы эти слова по- пали в результат, необходимо добавить альтернативный выбор (^|\s) — для начала строки и (\s|$) — для конца строки. Чтобы найденные выражения внутри круглых скобок не по- пали в результат, следует добавить символы ?: после открывающей скобки: >>> re.findall(r"(?:^|\s)\-([a-z0-9]+)(?:\s|$)", s, re.S | re.I) ['word1', 'word3', 'word5'] Здесь первое и последнее слова успешно попали в результат. Почему же слова word2 и word4 не попали в список совпадений — ведь перед дефисом есть пробел и после слова есть про- бел? Чтобы понять причину, рассмотрим поиск по шагам. Первое слово успешно попадает в результат, т. к. перед дефисом расположено начало строки и после слова есть пробел. По- сле поиска указатель перемещается, и строка для дальнейшего поиска примет следующий вид: "-word1 <Указатель>-word2 -word3 -word4 -word5" Обратите внимание на то, что перед фрагментом -word2 больше нет пробела, и дефис не расположен в начале строки. Поэтому следующим совпадением окажется слово word3 , и указатель снова будет перемещен: "-word1 -word2 -word3 <Указатель>-word4 -word5" Опять перед фрагментом -word4 нет пробела, и дефис не расположен в начале строки. По- этому следующим совпадением окажется слово word5 , и поиск будет завершен. Таким обра- зом, слова word2 и word4 не попадают в результат, поскольку пробел до фрагмента уже был использован в предыдущем поиске. Чтобы этого избежать, следует воспользоваться поло- жительным просмотром вперед (?=...) : >>> re.findall(r"(?:^|\s)\-([a-z0-9]+)(?=\s|$)", s, re.S | re.I) ['word1', 'word2', 'word3', 'word4', 'word5'] Глава 7. Регулярные выражения 131 В этом примере мы заменили фрагмент (?:\s|$) на (?=\s|$) . Поэтому все слова успешно попали в список совпадений. 7.2. Поиск первого совпадения с шаблоном Для поиска первого совпадения с шаблоном предназначены следующие функции и методы: match() — проверяет соответствие с началом строки. Формат метода: match(<Строка>[, <Начальная позиция>[, <Конечная позиция>]]) Если соответствие найдено, возвращается объект Match , в противном случае — значение None : >>> import re >>> p = re.compile(r"[0-9]+") >>> print("Найдено" if p.match("str123") else "Нет") Нет >>> print("Найдено" if p.match("str123", 3) else "Нет") Найдено >>> print("Найдено" if p.match("123str") else "Нет") Найдено Вместо метода match() можно воспользоваться функцией match() . Формат функции: re.match(<Шаблон>, <Строка>[, <Модификатор>]) В параметре <Шаблон> указывается строка с регулярным выражением или скомпилиро- ванное регулярное выражение. В параметре <Модификатор> можно указать флаги, ис- пользуемые в функции compile() . Если соответствие найдено, то возвращается объект Match , в противном случае — значение None : >>> p = r"[0-9]+" >>> print("Найдено" if re.match(p, "str123") else "Нет") Нет >>> print("Найдено" if re.match(p, "123str") else "Нет") Найдено >>> p = re.compile(r"[0-9]+") >>> print("Найдено" if re.match(p, "123str") else "Нет") Найдено search() — проверяет соответствие с любой частью строки. Формат метода: search(<Строка>[, <Начальная позиция>[, <Конечная позиция>]]) Если соответствие найдено, возвращается объект Match , в противном случае — значение None : >>> p = re.compile(r"[0-9]+") >>> print("Найдено" if p.search("str123") else "Нет") Найдено >>> print("Найдено" if p.search("123str") else "Нет") Найдено >>> print("Найдено" if p.search("123str", 3) else "Нет") Нет Вместо метода search() можно воспользоваться функцией search() . Формат функции: re.search(<Шаблон>, <Строка>[, <Модификатор>]) 132 Часть I. Основы языка Python В параметре <Шаблон> указывается строка с регулярным выражением или скомпилиро- ванное регулярное выражение. В параметре <Модификатор> можно указать флаги, ис- пользуемые в функции compile() . Если соответствие найдено, возвращается объект Match , в противном случае — значение None : >>> p = r"[0-9]+" >>> print("Найдено" if re.search(p, "str123") else "Нет") Найдено >>> p = re.compile(r"[0-9]+") >>> print("Найдено" if re.search(p, "str123") else "Нет") Найдено fullmatch() — выполняет проверку, соответствует ли переданная строка регулярному выражению целиком. Формат метода: fullmatch(<Строка>[, <Начальная позиция>[, <Конечная позиция>]]) Если соответствие найдено, то возвращается объект Match , в противном случае — значе- ние None : >>> p = re.compile("[Pp]ython") >>> print("Найдено" if p.fullmatch("Python") else "Нет") Найдено >>> print("Найдено" if p.fullmatch("py") else "Нет") Нет >>> print("Найдено" if p.fullmatch("PythonWare") else "Нет") Нет >>> print("Найдено" if p.fullmatch("PythonWare", 0, 6) else "Нет") Найдено Вместо метода fullmatch() можно воспользоваться функцией fullmatch() . Формат функции: re.fullmatch(<Шаблон>, <Строка>[, <Модификатор>]) В параметре <Шаблон> указывается строка с регулярным выражением или скомпилиро- ванное регулярное выражение. В параметре <Модификатор> можно указать флаги, используемые в функции compile() . Если строка полностью совпадает с шаблоном, воз- вращается объект Match , в противном случае — значение None : >>> p = "[Pp]ython" >>> print("Найдено" if re.fullmatch(p, "Python") else "Нет") Найдено >>> print("Найдено" if re.fullmatch(p, "py") else "Нет") Нет В качестве примера переделаем нашу программу суммирования произвольного количества целых чисел, введенных пользователем (см. листинг 4.12), таким образом, чтобы при вводе строки вместо числа программа не завершалась с фатальной ошибкой. Предусмотрим также возможность ввода отрицательных целых чисел (листинг 7.5). Листинг 7.5. Суммирование произвольного количества чисел # -*- coding: utf-8 -*- import re print("Введите слово 'stop' для получения результата") summa = 0 Глава 7. Регулярные выражения 133 p = re.compile(r"^[-]?[0-9]+$", re.S) while True: x = input("Введите число: ") if x == "stop": break # Выход из цикла if not p.search(x): print("Необходимо ввести число, а не строку!") continue # Переходим на следующую итерацию цикла x = int(x) # Преобразуем строку в число summa += x print("Сумма чисел равна:", summa) input() Объект Match , возвращаемый методами (функциями) match() , search() и fullmatch() , име- ет следующие атрибуты и методы: re — ссылка на скомпилированный шаблон, указанный в методах (функциях) match() , search() и fullmatch() . Через эту ссылку доступны следующие атрибуты: • groups — количество групп в шаблоне; • groupindex — словарь с названиями групп и их номерами; • pattern — исходная строка с регулярным выражением; • flags — комбинация флагов, заданных при создании регулярного выражения в функции compile() , и флагов, указанных в самом регулярном выражении, в конст- рукции (?aiLmsux) ; string — значение параметра <Строка> в методах (функциях) match() , search() и fullmatch() ; pos — значение параметра <Начальная позиция> в методах match() , search() и fullmatch() ; endpos — значение параметра <Конечная позиция> в методах match() , search() и fullmatch() ; lastindex — возвращает номер последней группы или значение None , если поиск завер- шился неудачей; lastgroup — возвращает название последней группы или значение None , если эта группа не имеет имени или поиск завершился неудачей: >>> p = re.compile(r"(?P >>> m = p.search("123456string 67890text") >>> m <_sre.SRE_Match object at 0x00FC9DE8> >>> m.re.groups, m.re.groupindex (2, {'num': 1, 'str': 2}) >>> p.groups, p.groupindex (2, {'num': 1, 'str': 2}) >>> m.string '123456string 67890text' >>> m.lastindex, m.lastgroup (2, 'str') >>> m.pos, m.endpos (0, 22) 134 Часть I. Основы языка Python group([ — возвращает фрагменты, соответ- ствующие шаблону. Если параметр не задан или указано значение 0 , возвращается фрагмент, полностью соответствующий шаблону. Если указан номер или название груп- пы, возвращается фрагмент, совпадающий с этой группой. Через запятую можно указать несколько номеров или названий групп — в этом случае возвращается кортеж, содер- жащий фрагменты, что соответствует группам. Если нет группы с указанным номером или названием, то возбуждается исключение IndexError : >>> p = re.compile(r"(?P >>> m = p.search("123456string 67890text") >>> m.group(), m.group(0) # Полное соответствие шаблону ('123456string', '123456string') >>> m.group(1), m.group(2) # Обращение по индексу ('123456', 'string') >>> m.group("num"), m.group("str") # Обращение по названию ('123456', 'string') >>> m.group(1, 2), m.group("num", "str") # Несколько параметров (('123456', 'string'), ('123456', 'string')) groupdict([<Значение по умолчанию>]) — возвращает словарь, содержащий значения именованных групп. С помощью необязательного параметра можно указать значение, которое будет выводиться вместо значения None для групп, не имеющих совпадений: >>> p = re.compile(r"(?P >>> m = p.search("123456") >>> m.groupdict() {'num': '123456', 'str': None} >>> m.groupdict("") {'num': '123456', 'str': ''} groups([<Значение по умолчанию>]) — возвращает кортеж, содержащий значения всех групп. С помощью необязательного параметра можно указать значение, которое будет выводиться вместо значения None для групп, не имеющих совпадений: >>> p = re.compile(r"(?P >>> m = p.search("123456") >>> m.groups() ('123456', None) >>> m.groups("") ('123456', '') start([<Номер или название группы>]) — возвращает индекс начала фрагмента, соот- ветствующего заданной группе. Если параметр не указан, то фрагментом является пол- ное соответствие с шаблоном. Если соответствия нет, возвращается значение -1 ; end([<Номер или название группы>]) — возвращает индекс конца фрагмента, соответ- ствующего заданной группе. Если параметр не указан, то фрагментом является полное соответствие с шаблоном. Если соответствия нет, возвращается значение -1 ; span([<Номер или название группы>]) — возвращает кортеж, содержащий начальный и конечный индексы фрагмента, соответствующего заданной группе. Если параметр не указан, то фрагментом является полное соответствие с шаблоном. Если соответствия нет, возвращается значение (–1, -1) : Глава 7. Регулярные выражения 135 >>> p = re.compile(r"(?P >>> s = "str123456str" >>> m = p.search(s) >>> m.start(), m.end(), m.span() (3, 12, (3, 12)) >>> m.start(1), m.end(1), m.start("num"), m.end("num") (3, 9, 3, 9) >>> m.start(2), m.end(2), m.start("str"), m.end("str") (9, 12, 9, 12) >>> m.span(1), m.span("num"), m.span(2), m.span("str") ((3, 9), (3, 9), (9, 12), (9, 12)) >>> s[m.start(1):m.end(1)], s[m.start(2):m.end(2)] ('123456', 'str') expand(<Шаблон>) — производит замену в строке. Внутри указанного шаблона можно использовать обратные ссылки: \номер группы , \g<номер группы> и \g<название группы> Для примера поменяем два тега местами: >>> p = re.compile(r"<(?P >>> m = p.search(" |