[Основы разработки поискового робота на Python ②] Основы Python (регулярные выражения)

  • Дружеское напоминание : поскольку статьи в этой колонке ориентированы на краулеров, невозможно осветить все о питоне, здесь мы сосредоточимся только на ключевых моментах.
    Если вы чувствуете, что есть что-то, что не было упомянуто, добро пожаловать в добавление~

  • Предыдущие рекомендации : [Основы разработки поискового робота на Python ①] Основы Python (1)
    В предыдущей статье уже говорилось об основных типах переменных Python, сегодня мы рассмотрим «регулярные выражения», которые Python чаще всего использует при разработке поискового робота.



1 Что такое регулярное выражение

Регулярное выражение (regular expression, часто сокращенно regex, regexp или RE в коде) — это шаблонная строка, используемая для поиска, замены, разделения и сопоставления текстовых данных . Основная идея состоит в том , чтобы использовать некоторые специальные символы для представления заданного шаблона , а затем сопоставлять этот шаблон в тексте.

Роль регулярных выражений:

  1. Соответствие : определить, соответствует ли данная строка логике фильтра регулярного выражения;
  2. Получить подстроку : мы можем получить нужную часть строки с помощью регулярных выражений.

Особенности регулярных выражений:

  1. Очень сильная гибкость, логика и функциональность ;
  2. Сложное управление струнами может быть быстро достигнуто чрезвычайно простым способом .
  3. Для тех, кто впервые в контакте, это относительно неясно.

2 Использование регулярных выражений в Python

В Python модуль re и модуль regex в основном используются для реализации операций с регулярными выражениями. Ниже приведены подробные пояснения соответственно.

2.1 ре модуль

Модуль Python re (регулярные выражения) — это мощный и гибкий инструмент для сопоставления с образцом, замены и разделения строк . Модуль re можно использовать для обработки различных символьных данных, включая текстовые файлы, файлы журналов, коды языков программирования и многое другое. Модуль re содержит большое количество функций регулярных выражений, включая поиск, замену, разделение, сопоставление, копирование, извлечение и т. д., которые могут помочь пользователям эффективно выполнять задачи по обработке текста.

Примечание . Python поставляется с модулем re, дополнительная установка не требуется. Поэтому также очень удобно использовать модуль re без запуска команды pip install в терминале, как при установке других сторонних библиотек.

2.1.1 поиск()

re.search() — это функция, обычно используемая в модуле Python re, которая используется для поиска заданного шаблона регулярного выражения в строке . При поиске функция будет сканировать всю строку , пока не найдет первую подстроку строки, соответствующую шаблону, а затем вернет соответствующий объект (Match Object). Если совпадающая подстрока не найдена, функция возвращает None.

Обычно функция re.search() используется следующим образом:

match_object = re.search(pattern, string, flags=0)

Среди них параметр шаблона указывает регулярное выражение для сопоставления, параметр строки указывает строку для сопоставления, а параметр флагов указывает параметр сопоставления (например, игнорировать ли регистр и т. д.). Когда функция возвращает совпадающий объект, вы можете вызвать метод match_object.group() для получения совпадающей подстроки , а параметр этого метода представляет собой порядковый номер получаемой подстроки (если в регулярном выражении несколько скобок , каждая скобка обозначает группу, чей порядковый номер увеличивается слева направо).

Например, вот пример кода для поиска регулярного выражения в строке:

import re

text = "Python is a popular programming language"
pattern = "programming"
match_object = re.search(pattern, text)

if match_object:
    print("Found a match:", match_object.group())
else:
    print("No match found.")

Выходной результат:

Found a match: programming

2.1.2 re.match()

В Python модуль re.match() аналогичен модулю re.search(), который используется для поиска совпадений регулярных выражений в строках. Однако re.match() будет соответствовать только началу строки, и если в начале не будет найдено совпадений, он вернет объект None . Таким образом, re.match() больше подходит для сценариев, в которых требуется совпадение в начале строки.

Использование функции match такое же, как и для поиска Давайте посмотрим на ту же тестовую строку и результат, возвращаемый match:

text = "Python is a popular programming language"
pattern = "programming"
match_object = re.match(pattern, text)

if match_object:
    print("Found a match:", match_object.group())
else:
    print("No match found.")

выход:

No match found.

Поскольку программирование — это не первое слово, оно не может совпадать.

2.1.3 re.findall()

re.findall() — еще одна функция сопоставления шаблонов, предоставляемая модулем re в Python. Она может искать все шаблоны, соответствующие регулярным выражениям в строке, и возвращать список. Каждый элемент в списке совпадает с регулярным выражением. подстрока . В отличие от and
возвращаются все совпадения , а не только первое или последнее совпадение. Поэтому это очень полезная функция , если вам нужно найти все экземпляры шаблона в тексте, соответствующие определенному регулярному выражению .re.search()re.match()re.findall()re.findall()

Вот пример кода для этой функции:

import re

# 定义一个正则表达式,匹配以数字开头的子字符串
pattern = r'\d+'

# 定义一个待匹配的字符串
text = "Today is Oct 15, 2021, and the temperature is 20 degrees Celsius."

# 使用re.findall()函数查找所有匹配项,并将它们存储在一个list对象中
matches = re.findall(pattern, text)

# 输出匹配结果
print(matches)

В этом примере мы сначала определяем шаблон регулярного выражения r'\d+'для сопоставления подстрок, начинающихся с цифры. Затем мы определяем строку для сопоставления, text. Далее мы re.findall()находим все совпадения с помощью функции и сохраняем их в объекте списка matches. Наконец, мы выводим совпадающие результаты на экран.

Выходной результат:

['15', '2021', '20']

Это связано с тем, что в тексте примера есть три подстроки, начинающиеся с цифры, а именно 15, 2021 и 20 градусов. re.findall()функция находит их и сохраняет в объекте списка.

2.1.4 re.sub()

re.sub() — это еще одна функция сопоставления шаблонов, представленная в модуле Python re, которая используется для замены подстроки, соответствующей определенному шаблону в строке . Функция re.sub() возвращает новую строку , в которой все подстроки, соответствующие указанному шаблону, заменены указанным содержимым.

Вот простой пример кода использования re.sub() для подстановки строк:

import re

# 定义一个正则表达式,匹配所有'is'字符
pattern = 'is'

# 定义一个待匹配的字符串
text = "The pattern of the book is not easy to find."

# 使用re.sub()函数将匹配项替换为指定字符串
new_text = re.sub(pattern, "was", text)

# 输出结果
print(new_text)

В этом примере мы сначала определяем шаблон регулярного выражения, 'is'который соответствует всем isсимволам. Затем мы определяем строку для сопоставления, text. Затем мы используем re.sub()функцию для замены всех совпадений на "was". Наконец, мы выводим новую строку после замены.

выход:

The pattern of the book was not easy to find.

2.2 модуль регулярных выражений

В дополнение к модулю re в стандартной библиотеке есть некоторые сторонние модули регулярных выражений, такие как модуль regex, которые предоставляют функции, которые являются более полными, расширенными и совместимыми с синтаксисом регулярных выражений Perl, чем модуль re.

Модуль regex подобен модулю re, предоставляя большинство функций модуля re, но он поддерживает больше синтаксиса и функций регулярных выражений, таких как сложные утверждения, атрибуты Unicode и сопоставление вложенных структур. Кроме того, производительность модуля regex также выше, чем у модуля re, который может обрабатывать большие регулярные выражения и более длинные текстовые данные.

Короче говоря, в Python существует множество модулей регулярных выражений, среди которых наиболее часто используется модуль re в стандартной библиотеке. Если вам нужен более сложный синтаксис и функциональность при работе с регулярными выражениями, вы можете попробовать модуль regex.


3 Классификация регулярных выражений

Регулярное выражение состоит из некоторых обычных символов и некоторых метасимволов (метасимволов). Обычные символы включают прописные и строчные буквы и цифры, в то время как метасимволы имеют особое значение, которое является токенами, которые мы хотим использовать для сопоставления.

3.1 Простые метасимволы

метасимвол эффект
\ Помещает токен следующего символа, обратную ссылку или восьмеричное escape-последовательность.
^ Соответствует началу входной строки.
$ Совпадение с концом строки ввода.
(звездочка)* Соответствует предыдущему подвыражению любое количество раз.
(плюс) + Соответствует предыдущему подвыражению один или несколько раз (больше или равно 1 разу).
? Соответствует предыдущему подвыражению ноль или один раз.

Образец кода:

import re
# 匹配开头字符
res1 = re.match('^a', 'abandon')
print(res1)			# <re.Match object; span=(0, 1), match='a'>
print(res1.group())	# a
# 匹配结尾字符
res2 = re.match('.*d$', 'wood')
print(res2)			# <re.Match object; span=(0, 4), match='wood'>
print(res2.group())	# wood
# 匹配至少出现一次的字符
res3 = re.match('a+', 'aabcd')
print(res3)			# <re.Match object; span=(0, 2), match='aa'>
print(res3.group())	# aa
# 匹配一次或零次的字符
res4 = re.match('a?', 'aaabandon')
print(res4)			# <re.Match object; span=(0, 1), match='a'>
print(res4.group())	# a

3.2 Метасимволы для односимвольного сопоставления

метасимвол эффект
. (точка) Соответствует любому одиночному символу, кроме "\n" и "\r".
\ д Соответствует числовому символу.
Соответствует нечисловому символу.
\f Соответствует символу перевода формы.
\n Соответствует символу новой строки.
Соответствует возврату каретки.
Соответствует любому невидимому символу, включая пробелы, табуляции, переводы форм и т. д.
Соответствует любому видимому символу.
Соответствует символу табуляции.
Соответствует любому символу слова, включая символ подчеркивания.
\ Вт Соответствует любому символу, не являющемуся словом.

Примечание . Добавьте знак плюс (+) после метасимвола, чтобы он соответствовал одному или нескольким символам этого типа.

Пример кода один (.):

# 指定要匹配的模式
pattern = "py."
# 测试字符串1
test_str1 = "python"
result1 = re.match(pattern, test_str1)
print(result1)	# 输出 <re.Match object; span=(0, 3), match='pyt'>

Пример кода 2 (\d, \D):

# 指定要匹配的模式
pattern = "\d"
# 测试字符串2
test_str2 = "The price is 199.99 dollars"
result2 = re.findall(pattern, test_str2)
print(result2)  # 输出['1', '9', '9', '9', '9']

# 指定要匹配的模式
pattern = "\D"

# 测试字符串3
test_str3 = "My phone number is 555-1234"
result3 = re.findall(pattern, test_str3)
print(result3)  # 输出 ['M', 'y', ' ', 'p', 'h', 'o', 'n', 'e', ' ', 'n', 'u', 'm', 'b', 'e', 'r', ' ', 'i', 's', ' ', '-']

Пример кода четыре (\s, \S):

# 指定要匹配的模式
pattern1 = r"\s+"  # 匹配一个或多个空白字符
pattern2 = r"\S+"  # 匹配一个或多个非空白字符

# 测试字符串1
test_str1 = "Hello\tworld\n"
result1 = re.findall(pattern1, test_str1)
print(result1)  # 输出 ['\t', '\n']

result2 = re.findall(pattern2, test_str1)
print(result2)  # 输出 ['Hello', 'world']

# 测试字符串2
test_str2 = " This is a demo. "
result3 = re.findall(pattern1, test_str2)
print(result3)  # 输出 [' ', ' ', ' ']

result4 = re.findall(pattern2, test_str2)
print(result4)  # 输出 ['This', 'is', 'a', 'demo.']

Пример кода четыре (\w, \W):

# 指定要匹配的模式
pattern1 = r"\w+"  # 匹配一个或多个单词字符
pattern2 = r"\W+"  # 匹配一个或多个非单词字符

# 测试字符串1
test_str1 = "Hello, world!"
result1 = re.findall(pattern1, test_str1)
print(result1)  # 输出 ['Hello', 'world']

result2 = re.findall(pattern2, test_str1)
print(result2)  # 输出 [', ', '!']

# 测试字符串2
test_str2 = "This is a demo."
result3 = re.findall(pattern1, test_str2)
print(result3)  # 输出 ['This', 'is', 'a', 'demo']

result4 = re.findall(pattern2, test_str2)
print(result4)  # 输出 [' ', ' ', ' ', '.']

3.3 Метасимволы для сопоставления наборов символов

метасимвол эффект
[xyz] коллекция персонажей. Соответствует любому из содержащихся символов.

Пример кода :

import re

# 指定要匹配的模式
pattern1 = r"[aeiou]"  # 匹配任何元音字母
pattern2 = r"[A-Z]"   # 匹配任何大写字母

# 测试字符串1
test_str1 = "Hello, world!"
result1 = re.findall(pattern1, test_str1)
print(result1)  # 输出 ['e', 'o', 'o']

# 测试字符串2
test_str2 = "This is a Demo."
result2 = re.findall(pattern2, test_str2)
print(result2)  # 输出 ['T', 'D']

3.4 Метасимволы для сопоставления квантификаторов

метасимвол эффект
{п} n — целое неотрицательное число. Совпадение определено n раз.
{п,} n — целое неотрицательное число. Совпадение не менее n раз.
{н, м} И m, и n — неотрицательные целые числа, где n<=m. Совпадение не менее n раз и не более m раз.

Пример кода :

import re

# 指定要匹配的模式
pattern1 = r"[a-z]{3}"  # 匹配任何由三个小写字母组成的连续子串
pattern2 = r"\d{2,3}"   # 匹配任何由两个或三个数字组成的连续子串

# 测试字符串1
test_str1 = "apple banana cherry"
result1 = re.match(pattern1, test_str1)
print(result1)  # 输出 <re.Match object; span=(0, 3), match='app'>

# 测试字符串2
test_str2 = "1234567890 12 123 1234"
result2 = re.findall(pattern2, test_str2)
print(result2)  # 输出 ['12', '123', '234']

3.5 Метасимволы для группового сопоставления

метасимвол эффект
() Определите выражение между ( и ) как «группу» и сохраните символы, соответствующие этому выражению, в кортеж.

Пример кода :

# 指定要匹配的模式
pattern1 = r"(\d{3})-(\d{4})-(\d{4})"  # 匹配格式为 3-4-4 的电话号码
pattern2 = r"<(\w+)>.*</\1>"   # 匹配任何形如 <tag>value</tag> 的 XML 节点

# 测试字符串1
test_str1 = "My phone number is 123-4567-8901."
result1 = re.search(pattern1, test_str1)
if result1:
    area_code, prefix, line_number = result1.groups()
    print("Area code: {}, Prefix: {}, Line number: {}".format(area_code, prefix, line_number))
else:
    print("No match.")

# 测试字符串2
test_str2 = "<title>This is a title</title>"
result2 = re.match(pattern2, test_str2)
if result2:
    tag = result2.group(1)
    print("Tag name: {}".format(tag))
else:
    print("No match.")

выход:

Area code: 123, Prefix: 4567, Line number: 8901
Tag name: title

В приведенном выше примере мы определили два шаблона (\d{3})-(\d{4})-(\d{4})(где ()означает использование содержащегося в нем набора символов в качестве группы захвата, groups()а содержимое группы можно получить с помощью метода при последующей обработке) и <(\w+)>.*</\1>(где \1означает обращение к первому захвату группировать совпадающий контент). Затем мы используем re.searchэту функцию для поиска двух разных тестовых строк, чтобы увидеть, соответствуют ли они этим шаблонам. Первая тестовая строка содержит номер телефона в 3-4-4формате , мы сопоставили его и дополнительно извлекли код города, префикс и информацию о номере строки номера. А вторая тестовая строка — это XML-узел, мы сопоставили его и дополнительно извлекли имя узла.
Вы можете изменить этот пример по мере необходимости, чтобы реализовать более сложные функции обработки текста.

  • Наконец, есть метасимвол «|», который используется для выполнения логической операции «или» (или) над двумя совпадающими условиями .

Пример кода выглядит следующим образом:

# 指定要匹配的模式
pattern = r"(cat|dog|bird)\d*"  # 匹配任何形如 cat\d* 或 dog\d* 或 bird\d* 的字符串

# 测试字符串
test_str = "I have a cat3 and a dog4 but no bird."
results = re.findall(pattern, test_str)
if results:
    print("Matching results: ", results)
else:
    print("No match.")

выход:

Matching results:  ['cat', 'dog', 'bird']

4 Эквивалентность регулярных выражений

Regex трудно понять, потому что в нем есть понятие эквивалентности.Это понятие значительно усложняет понимание и сбивает с толку многих новичков.Если вы восстановите эквивалентность исходному способу написания, будет очень просто написать регулярное выражение. выражения сами, так же, как и говорить Пришло время написать свое регулярное выражение

?,*,+,\d,\w все эквивалентные символы

  • ? Эквивалентно совпадающей длине {0,1}
  • * Эквивалентно соответствующей длине {0,}
  • + эквивалентно соответствующей длине {1,}
  • \d эквивалентно [0-9]
  • \D эквивалентно [^0-9]
  • \w эквивалентно [A-Za-z_0-9]
  • \W эквивалентно [^A-Za-z_0-9].

5 жадное соответствие

Жадное сопоставление и нежадное сопоставление регулярных выражений означают, что при наличии нескольких возможных совпадающих текстов в регулярном выражении выбираются разные методы сопоставления.

Жадное сопоставление означает максимально возможное сопоставление всех квалифицированных строк при сопоставлении, то есть сначала сопоставление более длинных текстов . Например, a.*bозначает aначинающийся с и bзаканчивающийся на , и любой символ (включая пробелы) в середине появляется хотя бы один раз, и механизм регулярных выражений выберет как можно больше символов из крайнего левого положения, чтобы выполнить условие при сопоставлении строки, которая удовлетворяет правило. Например, для строк abbbcbbbdрезультатом жадного сопоставления этого регулярного выражения является abbbcbbb.

Соответственно, нежадное сопоставление также называется ленивым сопоставлением или минимальным сопоставлением, что означает сопоставление только самой короткой строки, удовлетворяющей условиям во время сопоставления . По умолчанию механизм регулярных выражений использует режим жадного сопоставления, добавляя префикс ? после того, как квантификатор может преобразовать его в режим нежадного сопоставления . Например, a.*?bэто означает , что оно aначинается с и bзаканчивается на , и любой символ (включая пробелы) в середине встречается хотя бы один раз, а ?после добавления это означает, что это правило выполняется при кратчайшем возможном условии. Например, для строк abbbcbbbdрезультатом нежадного сопоставления этого регулярного выражения является abb.

  • Жадное или нежадное сопоставление регулярных выражений зависит от того, стоит ли после квантификатора вопросительный знак, который следует определять в соответствии с фактическими потребностями. Обратите внимание, что, хотя нежадный поиск обычно безопаснее и надежнее, он также приводит к снижению производительности, поскольку движку необходимо постоянно возвращаться, чтобы найти подходящий текст.

Пример кода :

# 原始字符串
str1 = "hello-world-and-hi"

# 贪婪匹配,获取第一个连字符到最后一个连字符之间的所有字符
result1_greedy = re.findall(r"-.*-", str1)
print(result1_greedy)    # 输出 ['-world-and-']

# 非贪婪匹配,只获取第一个连字符到第二个连字符之间的所有字符
result1_non_greedy = re.findall(r"-\w+?-", str1) 
print(result1_non_greedy)   # 输出 ['-world-']

# 原始字符串
s = "hello world, this is a test string."

# 贪婪匹配,获取以 h 开头、以空格结尾的所有字符
result_greedy = re.findall(r"h.* ", s)
print(result_greedy)	# ['hello world, this is a test ']

# 非贪婪匹配,获取以 h 开头、以空格结尾的最短字符
result_non_greedy = re.findall(r"h.*? ", s)
print(result_non_greedy)	# ['hello ', 'his ']

рекомендация

отblog.csdn.net/z135733/article/details/131078962