[Grundlagen der Python-Crawler-Entwicklung ②] Python-Grundlagen (reguläre Ausdrücke)

  • Freundliche Erinnerung : Da die Artikel in dieser Kolumne auf Crawler ausgerichtet sind, ist es unmöglich, alles über Python abzudecken. Hier konzentrieren wir uns nur auf die wichtigsten Punkte.
    Wenn Sie das Gefühl haben, dass etwas nicht erwähnt wurde, können Sie es gerne hinzufügen~

  • Frühere Empfehlungen : [Grundlagen der Python-Crawler-Entwicklung ①] Python-Grundlagen (1)
    Im vorherigen Artikel wurde bereits über die grundlegenden Variablentypen von Python gesprochen. Heute werfen wir einen Blick auf die „regulären Ausdrücke“, die Python in der Crawler-Entwicklung häufiger verwendet.



1 Was ist ein regulärer Ausdruck?

Ein regulärer Ausdruck (regulärer Ausdruck, im Code oft als Regex, Regexp oder RE abgekürzt) ist eine strukturierte Zeichenfolge, die zum Suchen, Ersetzen, Teilen und Abgleichen von Textdaten verwendet wird . Die Grundidee besteht darin, einige Sonderzeichen zur Darstellung eines bestimmten Musters zu verwenden und dieses Muster dann im Text abzugleichen.

Die Rolle regulärer Ausdrücke:

  1. Matching : Bestimmen Sie, ob eine bestimmte Zeichenfolge der Filterlogik des regulären Ausdrucks entspricht.
  2. Teilzeichenfolge erhalten : Wir können den gewünschten Teil aus der Zeichenfolge durch reguläre Ausdrücke erhalten.

Merkmale regulärer Ausdrücke:

  1. Sehr starke Flexibilität, Logik und Funktionalität ;
  2. Eine komplexe Steuerung von Strings kann schnell und auf äußerst einfache Weise erreicht werden .
  3. Für Neulinge ist der Kontakt relativ undurchsichtig.

2 Die Verwendung regulärer Ausdrücke in Python

In Python werden das re- Modul und das regex- Modul hauptsächlich zur Implementierung regulärer Ausdrucksoperationen verwendet. Im Folgenden finden Sie jeweils detaillierte Erläuterungen.

2.1 zum Modul

Das re-Modul (reguläre Ausdrücke) von Python ist ein leistungsstarkes und flexibles Werkzeug zum Mustervergleich, Ersetzen und Teilen von Zeichenfolgen . Das re-Modul kann zur Verarbeitung einer Vielzahl von Zeichendaten verwendet werden, darunter Textdateien, Protokolldateien, Programmiersprachencodes und mehr. Das re-Modul enthält eine große Anzahl regulärer Ausdrucksfunktionen, darunter Suchen, Ersetzen, Teilen, Abgleichen, Kopieren, Extrahieren usw., die Benutzern dabei helfen können, effiziente Textverarbeitungsaufgaben auszuführen.

Hinweis : Python wird mit dem re-Modul geliefert, es ist keine zusätzliche Installation erforderlich. Daher ist es auch sehr praktisch, das re-Modul zu verwenden, ohne den Befehl pip install im Terminal auszuführen, wie bei der Installation anderer Bibliotheken von Drittanbietern.

2.1.1 re.search()

re.search() ist eine Funktion, die häufig im Python-Re-Modul verwendet wird und zum Suchen nach einem bestimmten regulären Ausdrucksmuster in einer Zeichenfolge verwendet wird . Bei der Suche durchsucht die gesamte Zeichenfolge , bis sie die erste Teilzeichenfolge der Zeichenfolge findet, die mit dem Muster übereinstimmt, und gibt dann ein passendes Objekt (Match Object) zurück. Wenn kein passender Teilstring gefunden wird, gibt die Funktion None zurück.

Eine häufige Verwendung der Funktion re.search() ist wie folgt:

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

Unter diesen gibt der Musterparameter den abzugleichenden regulären Ausdruck an, der Zeichenfolgenparameter gibt die abzugleichende Zeichenfolge an und der Flags-Parameter gibt die Abgleichsoption an (z. B. ob die Groß-/Kleinschreibung ignoriert werden soll usw.). Wenn die Funktion ein übereinstimmendes Objekt zurückgibt, können Sie die Methode match_object.group() aufrufen, um die übereinstimmende Teilzeichenfolge abzurufen . Der Parameter dieser Methode stellt die Seriennummer der abzurufenden Teilzeichenfolge dar (sofern der reguläre Ausdruck mehrere Klammern enthält). , jede Klammer gibt eine Gruppe an, deren Seriennummer von links nach rechts zunimmt.

Hier ist beispielsweise ein Beispielcode zum Durchsuchen einer Zeichenfolge nach einem regulären Ausdruck:

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.")

Ausgabeergebnis:

Found a match: programming

2.1.2 re.match()

In Python ähnelt das Modul re.match() dem Modul re.search(), das zur Suche nach Übereinstimmungen regulärer Ausdrücke in Zeichenfolgen verwendet wird. Allerdings findet re.match() nur eine Übereinstimmung am Anfang der Zeichenfolge, und wenn am Anfang keine Übereinstimmung gefunden werden kann, wird ein None-Objekt zurückgegeben . Daher eignet sich re.match() besser für Szenarien, in denen eine Übereinstimmung am Anfang der Zeichenfolge erforderlich ist.

Die Funktionsverwendung von match ist dieselbe wie die von search. Schauen wir uns dieselbe Testzeichenfolge und das von match zurückgegebene Ergebnis an:

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.")

Ausgang:

No match found.

Da Programmierung nicht das erste Wort ist, kann es nicht übereinstimmen.

2.1.3 re.findall()

re.findall() ist eine weitere Mustervergleichsfunktion, die vom re-Modul in Python bereitgestellt wird. Sie kann nach allen Mustern suchen, die mit regulären Ausdrücken in einer Zeichenfolge übereinstimmen, und eine Liste zurückgeben. Jedes Element in der Liste ist mit dem regulären Ausdruck identisch. Mustervergleich Teilzeichenfolge . Im Gegensatz zu and
werden alle Übereinstimmungen zurückgegeben , nicht nur die erste oder letzte Übereinstimmung. Daher ist es eine sehr nützliche Funktion, wenn Sie alle Instanzen eines Musters in einem Text finden müssen, die einem bestimmten regulären Ausdruck entsprechen .re.search()re.match()re.findall()re.findall()

Hier ist Beispielcode für diese Funktion:

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)

In diesem Beispiel definieren wir zunächst ein reguläres Ausdrucksmuster, r'\d+'um Teilzeichenfolgen abzugleichen, die mit einer Zahl beginnen. Dann definieren wir eine Zeichenfolge, die abgeglichen werden soll text. Als nächstes finden wir re.findall()mithilfe der Funktion alle Übereinstimmungen und speichern sie in einem Listenobjekt matches. Abschließend geben wir die passenden Ergebnisse auf dem Bildschirm aus.

Ausgabeergebnis:

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

Dies liegt daran, dass es im Beispieltext drei Teilzeichenfolgen gibt, die mit einer Zahl beginnen, nämlich 15, 2021 und 20 Grad. re.findall()Die Funktion findet sie und speichert sie in einem Listenobjekt.

2.1.4 re.sub()

re.sub() ist eine weitere Mustervergleichsfunktion, die im Python-Re-Modul bereitgestellt wird und zum Ersetzen einer Teilzeichenfolge verwendet wird, die durch ein bestimmtes Muster in einer Zeichenfolge übereinstimmt . Die Funktion re.sub() gibt einen neuen String zurück , in dem alle Teilstrings, die dem angegebenen Muster entsprechen, durch den angegebenen Inhalt ersetzt werden.

Hier ist ein einfaches Codebeispiel für die Verwendung von re.sub() zur String-Ersetzung:

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)

In diesem Beispiel definieren wir zunächst ein reguläres Ausdrucksmuster, 'is'das mit allen isZeichen übereinstimmt. Dann definieren wir eine Zeichenfolge, die abgeglichen werden soll text. Als nächstes verwenden wir re.sub()die Funktion, um alle Übereinstimmungen durch zu ersetzen "was". Schließlich geben wir die neue Zeichenfolge nach dem Ersetzen aus.

Ausgang:

The pattern of the book was not easy to find.

2.2 Regex-Modul

Zusätzlich zum re-Modul in der Standardbibliothek gibt es einige reguläre Ausdrucksmodule von Drittanbietern, z. B. das Regex-Modul, die umfassendere, fortschrittlichere und mit der Perl-Syntax für reguläre Ausdrücke kompatiblere Funktionen bereitstellen als das re-Modul.

Das Regex-Modul ähnelt dem re-Modul und stellt die meisten Funktionen im re-Modul bereit, unterstützt jedoch mehr reguläre Ausdruckssyntax und -funktionen, wie z. B. komplexe Assertionen, Unicode-Attribute und passende verschachtelte Strukturen. Darüber hinaus ist die Leistung des Regex-Moduls besser als die des Re-Moduls, das größere reguläre Ausdrücke und längere Textdaten verarbeiten kann.

Kurz gesagt, es gibt viele reguläre Ausdrucksmodule in Python, von denen das re-Modul in der Standardbibliothek das am häufigsten verwendete ist. Wenn Sie beim Umgang mit regulären Ausdrücken eine komplexere Syntax und Funktionalität benötigen, können Sie das Regex-Modul ausprobieren.


3 Klassifizierung regulärer Ausdrücke

Ein regulärer Ausdruck besteht aus einigen gewöhnlichen Zeichen und einigen Metazeichen (Metazeichen). Zu den gewöhnlichen Zeichen gehören Groß- und Kleinbuchstaben sowie Zahlen, während Metazeichen eine besondere Bedeutung haben. Dabei handelt es sich um die Token, die wir für den Abgleich verwenden möchten.

3.1 Einfache Metazeichen

Metazeichen Wirkung
\ Fügt das nächste Zeichen-Token, eine Rückreferenz oder ein oktales Escapezeichen ein.
^ Entspricht dem Anfang der Eingabezeile.
$ Passen Sie das Ende der Eingabezeile an.
(Sternchen)* Entspricht dem vorhergehenden Unterausdruck beliebig oft.
(Pluszeichen) + Entspricht dem vorhergehenden Unterausdruck einmal oder mehrmals (größer oder gleich 1 Mal).
? Entspricht null oder einmal dem vorhergehenden Unterausdruck.

Beispielcode:

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 Metazeichen für den Einzelzeichenabgleich

Metazeichen Wirkung
. (Punkt) Entspricht jedem einzelnen Zeichen außer „\n“ und „\r“.
\D Entspricht einem numerischen Zeichen.
\D Entspricht einem nicht numerischen Zeichen.
\F Entspricht einem Formular-Feed-Zeichen.
\N Entspricht einem Zeilenumbruchzeichen.
\R Entspricht einem Wagenrücklauf.
\S Entspricht jedem unsichtbaren Zeichen, einschließlich Leerzeichen, Tabulatoren, Formularvorschüben usw.
\S Entspricht jedem sichtbaren Zeichen.
\T Entspricht einem Tabulatorzeichen.
\w Entspricht jedem Wortzeichen, einschließlich eines Unterstrichs.
\W Entspricht jedem Nicht-Wort-Zeichen.

Hinweis : Fügen Sie nach dem Metazeichen ein Pluszeichen (+) hinzu, um ein oder mehrere Zeichen dieses Typs zu finden

Codebeispiel eins (.):

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

Codebeispiel 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', ' ', '-']

Codebeispiel vier (\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.']

Codebeispiel vier (\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 Metazeichen für den Zeichensatzabgleich

Metazeichen Wirkung
[xyz] Sammlung von Charakteren. Entspricht einem der enthaltenen Zeichen.

Codebeispiel :

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 Metazeichen für Quantifier Matching

Metazeichen Wirkung
{N} n ist eine nicht negative ganze Zahl. Übereinstimmung n-mal ermittelt.
{N,} n ist eine nicht negative ganze Zahl. Passt mindestens n-mal zusammen.
{n,m} Sowohl m als auch n sind nicht negative ganze Zahlen, wobei n<=m. Übereinstimmung mindestens n-mal und höchstens m-mal.

Codebeispiel :

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 Metazeichen für den Gruppenvergleich

Metazeichen Wirkung
() Definieren Sie den Ausdruck zwischen ( und ) als „Gruppe“ und speichern Sie die diesem Ausdruck entsprechenden Zeichen in einem Tupel

Beispielcode :

# 指定要匹配的模式
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.")

Ausgang:

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

Im obigen Beispiel haben wir zwei Muster definiert (\d{3})-(\d{4})-(\d{4})(wobei ()bedeutet, dass der darin enthaltene Zeichensatz als Erfassungsgruppe verwendet groups()wird und der Inhalt der Gruppe durch die Methode in der nachfolgenden Verarbeitung abgerufen werden kann) und <(\w+)>.*</\1>(wobei \1bedeutet auf die erste Erfassung zu verweisen gruppenbezogener Inhalt). Anschließend verwenden wir re.searchdie Funktion um zwei verschiedene Testzeichenfolgen zu durchsuchen, um festzustellen, ob sie mit diesen Mustern übereinstimmen. Die erste Testzeichenfolge enthält eine Telefonnummer 3-4-4im , wir haben sie abgeglichen und weiter die Vorwahl-, Präfix- und Leitungsnummerninformationen der Nummer extrahiert. Und die zweite Testzeichenfolge ist ein XML-Knoten, wir haben ihn abgeglichen und den Namen des Knotens weiter extrahiert.
Sie können dieses Beispiel nach Bedarf ändern, um komplexere Textverarbeitungsfunktionen zu implementieren.

  • Schließlich gibt es ein Metazeichen „|“, das verwendet wird, um eine logische „Oder“-Operation (oder) für zwei übereinstimmende Bedingungen durchzuführen .

Der Beispielcode lautet wie folgt:

# 指定要匹配的模式
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.")

Ausgang:

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

4 Äquivalenz regulärer Ausdrücke

Regex ist schwer zu verstehen, da es ein Konzept der Äquivalenz enthält. Dieses Konzept erschwert das Verständnis erheblich und lässt viele Anfänger verwirrt erscheinen. Wenn Sie die Äquivalenz auf die ursprüngliche Schreibweise zurückführen, wird es sehr einfach, normal zu schreiben Ausdrücke selbst ausdrücken, genau wie beim Sprechen. Es ist Zeit, Ihren regulären Ausdruck zu schreiben

?,*,+,\d,\w sind alle gleichwertige Zeichen

  • ? Entspricht der passenden Länge {0,1}
  • *Entspricht der passenden Länge {0,}
  • + entspricht der passenden Länge {1,}
  • \d entspricht [0-9]
  • \D entspricht [^0-9]
  • \w entspricht [A-Za-z_0-9]
  • \W entspricht [^A-Za-z_0-9].

5 gieriges Matching

Greedy-Matching und Non-Greed-Matching regulärer Ausdrücke bedeuten, dass bei mehreren möglichen passenden Texten im regulären Ausdruck unterschiedliche Matching-Methoden gewählt werden.

Beim gierigen Abgleich geht es darum, alle qualifizierten Zeichenfolgen so weit wie möglich abzugleichen, d. h. zuerst den längeren Text abzugleichen . a.*bBedeutet beispielsweise, dass amit „beginnt“ und b„end“ und jedes Zeichen (einschließlich Leerzeichen) in der Mitte mindestens einmal vorkommt und die Engine für reguläre Ausdrücke so viele Zeichen wie möglich von ganz links auswählt, um die Bedingung zu erfüllen, wenn sie mit einer Zeichenfolge übereinstimmt, die diese erfüllt die Regel. Für Zeichenfolgen abbbcbbbdist das Greedy-Matching-Ergebnis dieses regulären Ausdrucks beispielsweise abbbcbbb.

Dementsprechend wird nicht gieriges Matching auch als Lazy Matching oder Minimum Matching bezeichnet, was sich darauf bezieht, nur die kürzeste Zeichenfolge abzugleichen, die die Bedingungen während des Matchings erfüllt . Standardmäßig verwendet die Engine für reguläre Ausdrücke den Greedy-Matching-Modus und fügt nach dem Quantifizierer ein ?-Präfix hinzu, um ihn in einen Non-Greedy-Matching-Modus umzuwandeln . a.*?bDies bedeutet beispielsweise, dass es amit beginnt und bendet und jedes Zeichen (einschließlich Leerzeichen) in der Mitte mindestens einmal vorkommt. ?Nach dem Hinzufügen bedeutet dies, dass diese Regel unter der kürzestmöglichen Bedingung erfüllt ist. Für Zeichenfolgen abbbcbbbdlautet das nicht gierige Übereinstimmungsergebnis dieses regulären Ausdrucks beispielsweise abb.

  • Der gierige oder nicht gierige Abgleich regulärer Ausdrücke hängt davon ab, ob nach dem Quantifizierer ein Fragezeichen steht, das entsprechend den tatsächlichen Anforderungen bestimmt werden sollte. Beachten Sie, dass Non-Greedy im Allgemeinen zwar sicherer und zuverlässiger ist, aber auch einen Leistungseinbußen mit sich bringt, da die Engine immer wieder zurückgehen muss, um geeigneten Text zu finden.

Beispielcode :

# 原始字符串
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 ']

Ich denke du magst

Origin blog.csdn.net/z135733/article/details/131078962
Empfohlen
Rangfolge