Dieser Artikel ist eine Fortsetzung meines Buches Einführung in Python mit 100 Knocking Language Processing. Ich werde [100 Schläge Kapitel 3] erklären (https://nlp100.github.io/ja/ch03.html).
In diesem Kapitel werden reguläre Ausdrücke verwendet. In Python wird es vom Modul "re" verwaltet. Um dieses Modul verwenden zu können, muss nicht nur der reguläre Ausdruck selbst, sondern auch die Methode und das Übereinstimmungsobjekt verstanden werden. Daher ist dies ziemlich schwierig. Ich denke nicht, dass es mehr ein Einstiegsniveau ist. Ich hatte nicht das Gefühl, einen besseren Kommentar als das Offizielle Tutorial schreiben zu können. Bitte lesen Sie ihn durch.
Kanonische Python-Ausdrücke sind jedoch langsam, daher versuche ich, sie so weit wie möglich zu vermeiden.
Laden Sie die Datei vorerst entsprechend herunter. * Diese Datei wird unter der nicht portablen Creative Commons Attribution-Inheritance 3.0-Lizenz verteilt. * *
$ wget https://nlp100.github.io/data/jawiki-country.json.gz
Gemäß der Problemstellung werden die Informationen eines Artikels pro Zeile im JSON-Format gespeichert. Das JSON-Format ist ein einfacher Export von Arrays und Wörterbüchern, und viele Programmiersprachen unterstützen dieses Format. Das Format dieser gesamten Datei heißt jedoch JSONL (JSON Lines). Schauen Sie sich den Inhalt der Datei mit $ gunzip -c jawiki-country.json.gz | less
usw. an (möglicherweise sehen Sie ihn direkt mit less
).
json Python hat auch eine Bibliothek, um diesen JSON einfach zu handhaben. Sein Name ist auch json. Dies ist ein Beispiel aus Dokument, aber es macht einen JSON-String zu einem Python-Objekt wie diesem und umgekehrt. Das ist sehr einfach.
import json
dic = json.loads('{"bar":["baz", null, 1.0, 2]}')
print(type(dic))
print(dic)
<class 'dict'>
{'bar': ['baz', None, 1.0, 2]}
dumped = json.dumps(dic)
print(type(dumped))
print(dumped)
<class 'str'>
{"bar": ["baz", null, 1.0, 2]}
Da es schwer zu verstehen war, habe ich auch den Typnamen mit "type ()" angezeigt. Übrigens bedeutet "s" in "Lades" und "Dumps" "String" anstelle von 3 Einheiten.
Lesen Sie die JSON-Datei des Wikipedia-Artikels und zeigen Sie den Artikeltext zu "UK" an. Führen Sie in den Problemen 21-29 den hier extrahierten Artikeltext aus.
Die heruntergeladene Datei ist im gz-Format, aber ich möchte sie nicht so weit wie möglich erweitern. Es ist besser, es mit Pythons gzip
-Modul zu lesen oder das Erweiterungsergebnis standardmäßig mit dem Unix-Befehl auszugeben und es mit einer Pipe zu verbinden.
Unten finden Sie ein Beispiel für die Antwort.
q20.py
import json
import sys
for line in sys.stdin:
wiki_dict = json.loads(line)
if wiki_dict['title'] == 'England':
print(wiki_dict.get('text'))
$ gunzip -c jawiki-country.json.gz | python q20.py > uk.txt
$ head -n5 uk.txt
{{redirect|UK}}
{{redirect|Vereinigtes Königreich|Ehrenländer im Frühjahr und Herbst|Englisch(Frühling und Herbst)}}
{{Otheruses|Europäisches Land|Lokale Küche der Präfekturen Nagasaki und Kumamoto|Igirisu}}
{{Grundinformationsland Abkürzung = Vereinigtes Königreich
Ich kann Weiterleitungen und Artikel mit demselben Namen erhalten, aber es sollte kein Problem geben.
Extrahieren Sie die Zeile, in der der Kategoriename im Artikel angegeben ist.
Siehe die Wikipedia Markup-Kurzreferenz und den Inhalt der eigentlichen Datei Lass uns darüber nachdenken.
Es scheint genug zu sein, um die Zeilen zu extrahieren, die mit "[[Kategorie" "beginnen. str.startswith (Präfix)
gibt den Wahrheitswert zurück, ob der String mit Präfix
beginnt.
Unten finden Sie ein Beispiel für die Antwort.
q21.py
import sys
for line in sys.stdin:
if line.startswith('[[Category'):
print(line.rstrip())
(Ich erinnere mich, dass die Version 2015 eine Mischung aus Kleinbuchstaben war, aber in der Version 2020 ist sie weg ...)
Extrahieren Sie die Namen der Artikelkategorien (nach Namen, nicht zeilenweise).
Es wird so sein, wenn Sie Ihre Hände schneiden.
q22.py
import sys
for line in sys.stdin:
print(line.lstrip("[Category:").rstrip("|*]\n"))
$ python q21.py < uk.txt | python q22.py
England Vereinigte Königreich Mitgliedsländer Königreich des Vereinigten Königreichs G8-Mitgliedsländer Mitgliedstaaten der Europäischen Union | Ehemalig Marine Nation Bestehendes souveränes Land Inselstaat Eine Nation / ein Gebiet, das 1801 gegründet wurde
Zeigen Sie die im Artikel enthaltenen Abschnittsnamen und deren Ebenen an (z. B. 1, wenn "== Abschnittsname ==").
Ändern Sie == Ländername ==
in Ländername 1
. Sie können das "Sub" in der Zeichenfolge mit "str.count (sub)" zählen.
Unten finden Sie ein Beispiel für eine Antwort, bei der keine regulären Ausdrücke verwendet werden.
q23.py
import sys
for line in sys.stdin:
if line.startswith('=='):
sec_name = line.strip('= \n')
level = int(line.count('=')/2 - 1)
print(sec_name, level)
Extrahieren Sie alle Mediendateien, auf die aus dem Artikel verwiesen wird.
Alle 2020 AusgabenDatei:Battle of Waterloo 1815.PNG|
Es ist so geformt.|
Verwenden Sie von nun an reguläre Ausdrücke, und beachten Sie, dass Sie sie entfernen möchten und dass sich möglicherweise mehr als einer in einer Zeile befindet. Das Testen regulärer Ausdrücke ist mit Online-Überprüfungswerkzeugen einfach.
Unten finden Sie ein Beispiel für die Antwort.
q24.py
import re
import sys
pat = re.compile(r'(Datei:)(?P<filename>.+?)\|')
for line in sys.stdin:
for match in pat.finditer(line):
print(match.group('filename'))
.+?\|
In "Nach so wenigen Wiederholungen eines Charakters wie möglich|
"Es bedeutet das. Bei der Betrachtung mehrerer Übereinstimmungenfinditer()
Ist bequem. Wenn es keine Übereinstimmung gibt, an erster Stellefor
Der Satz dreht sich nicht.
Das gleiche Ergebnis kann erhalten werden, selbst wenn das Argument "Gruppe" 2 ist.
Extrahieren Sie die Feldnamen und Werte der im Artikel enthaltenen Vorlage "Basisinformationen" und speichern Sie sie als Wörterbuchobjekt.
Es ist schwierig, mit den Feldern umzugehen, die in der Vorlage fehlerhaft sind.
{{Grundlegende Informationen Land
|Kurzbezeichnung=England
|Japanischer Ländername=Vereinigtes Königreich Großbritannien und Nordirland
|Offizieller Ländername= {{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>Offizieller Ländername außer Englisch:<br/>
*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[schottisch Gälisch]])<br/>
*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[Wales]])<br/>
Unten finden Sie ein Beispiel für die Antwort.
q25.py
import sys
import json
def main():
dic = extract_baseinf(sys.stdin)
sys.stdout.write(json.dumps(dic, ensure_ascii=False))
def extract_baseinf(fi):
baseinf = {}
isbaseinf = False
for line in fi:
if isbaseinf:
if line.startswith('}}'):
return baseinf
elif line[0] == '|':
templis = line.strip('|\n').split('=')
key = templis[0].rstrip()
value = "=".join(templis[1:]).lstrip()
baseinf[key] = value
else:
value = line.rstrip('\n')
baseinf[key] += f"\n{value}"
elif line.startswith('{{Grundinformation'):
isbaseinf = True
if __name__ == '__main__':
main()
!python q25.py < uk.txt > uk_baseinf.json
Wenn es mehrere Zeilen umfasst, wird es durch Verketten verarbeitet.
Ich werde es einmal an json schreiben, da der Code im nächsten Problem kompliziert sein wird. Zu diesem Zeitpunkt werden Zeichen verstümmelt, es sei denn, "sure_ascii = False" wird verwendet.
Entfernen Sie zum Zeitpunkt der Verarbeitung> 25 das MediaWiki-Hervorhebungsmarkup (alle schwachen Hervorhebungen, Hervorhebungen und starken Hervorhebungen) aus dem Vorlagenwert und konvertieren Sie es in Text (Referenz: [Markup-Kurzreferenz](http: // ja). wikipedia.org/wiki/Help:% E6% 97% A9% E8% A6% 8B% E8% A1% A8)).
Wenn '
2, 3 oder 5 Mal hintereinander erscheint, löschen Sie es. In Bezug auf den regulären Ausdruck sieht es aus wie "r" {2,5}. +? "{2,5}", aber es ist schwer, es ernsthaft zu tun. Wenn Sie dies ohne reguläre Ausdrücke tun, sieht es wie üblich so aus.
q26.py
import json
import sys
def main():
dic = json.loads(sys.stdin.read())
dic = remove_emphasis(dic)
print(json.dumps(dic, ensure_ascii=False, indent=4))
def remove_emphasis(dic):
for key, value in dic.items():
for n in (5, 3, 2):
eliminated = value.split("'" * n)
div, mod = divmod(len(eliminated), 2)
if mod == 1 and div > 0:
value = ''.join(eliminated)
dic[key] = value
return dic
if __name__ == '__main__':
main()
Der Ablauf besteht darin, die in der vorherigen Frage erstellte JSON-Datei aus der Standardeingabe zu lesen und den Wert des Wörterbuchobjekts zu ändern. dict.items ()
ist ein Iterator, der eine Reihe von (Schlüssel, Wert)
Paaren im Wörterbuch zurückgibt. Erinnern wir uns daran.
Wenn Sie "" in einem Zeichenfolgenliteral verwenden möchten, müssen Sie es maskieren oder in "" einschließen. Um dieselbe Zeichenfolge zusammenhängend zu machen, können Sie sie mit einem ganzzahligen Vielfachen multiplizieren. Und "split ()" Ich versuche, "" zu löschen und zu beurteilen, ob die Anzahl der Elemente in der zurückgegebenen Liste ungerade ist, damit ich keine unregelmäßigen "wie" a''b "lösche. Sie kann mit "%" berechnet werden, kann aber auch dann belassen werden, wenn der Quotient 0 ist. Wenn Sie also die integrierte Funktion "divmod ()" verwenden, werden der Quotient und der Rest gleichzeitig berechnet.
Der bedingte Ausdruck "A und B" ist für mich neu, aber Sie können ihn sehen, indem Sie ihn betrachten. Gleiches gilt für oder
. Wichtig ist die Bewertungsstrategie. Wenn sich herausstellt, dass "A und B" "A == Falsch" ist, endet die Auswertung des Ausdrucks ohne Auswertung von "B". Daher ist es effizienter, "A" wahrscheinlicher als "B" zu machen. In ähnlicher Weise bewertet "A" oder "B" "B" nicht, wenn sich herausstellt, dass es "A == Wahr" ist. Schreiben Sie also einen Ausdruck in "A", der eher "Wahr" ist.
Entfernen Sie zusätzlich zur Verarbeitung 26 das interne Link-Markup von MediaWiki aus dem Vorlagenwert und konvertieren Sie es in Text (Referenz: [Markup-Kurzreferenz](https://ja.wikipedia.org/wiki/Help :)). % E6% 97% A9% E8% A6% 8B% E8% A1% A8)).
Da es 3 Muster gibt, werden wir reguläre Ausdrücke verwenden.
q27.py
"""
[[Artikelüberschrift]]
[[Artikelüberschrift|Zeichen anzeigen]]
[[Artikelüberschrift#Abteilungsname|Zeichen anzeigen]]
"""
import json
import re
import sys
from q26 import remove_emphasis
def main():
dic = json.loads(sys.stdin.read())
dic = remove_emphasis(dic)
dic = remove_link(dic)
print(json.dumps(dic, ensure_ascii=False, indent=4))
def remove_link(dic):
pat = re.compile(r"""
\[\[ # [[
([^|]+\|)* #Artikelüberschrift|Nicht oder wiederholt
([^]]+) #Ersetzen Sie den Teil, der dem Anzeigezeichen pat entspricht, durch diesen
\]\] # ]]
""", re.VERBOSE)
for key, value in dic.items():
value = pat.sub(r'\2', value)
dic[key] = value
return dic
if __name__ == '__main__':
main()
Nach der Bearbeitung der vorherigen Frage können Sie den Wert des Wörterbuchs erneut ändern.
Sie können ein Zeichenfolgenliteral schreiben, das mehrere Zeilen umfasst, indem Sie es in dreifache Anführungszeichen setzen. Außerdem werden bei "re.VERBOSE" Leerzeichen, Zeilenumbrüche und Kommentare im regulären Ausdruck ignoriert, aber es ist immer noch schwer zu erkennen ...
Der Teil von "pat" (r "\ 2", Wert) bedeutet, den Teil von "Wert", der mit "pat" übereinstimmt, durch "Gruppe (2)" des Übereinstimmungsobjekts zu ersetzen. ..
Entfernen Sie zusätzlich zum> 27-Prozess MediaWiki-Markups so weit wie möglich aus den Vorlagenwerten und formatieren Sie grundlegende Länderinformationen.
Sie können es mit Pandoc und Pypandoc tun ... Wenn Sie mit regulären Ausdrücken Ihr Bestes geben, sollten Sie das hervorgehobene Markup, interne Links, Dateiverweise, externe Links, <ref>
, <br />
, {{0}}
, nur reguläre Ausdrücke, löschen. Ich werde es sagen ...
basic_info = re.compile(r"\|(.+?)\s=\s(.+)")
emphasize = re.compile(r"('+){2,5}(.+?)('+){2,5}")
link_inner = re.compile(r"\[\[(.+?)\]\]")
file_ref = re.compile(r"\[\[Datei:.+?\|.+?\|(.+?)\]\]")
ref = re.compile(r"<ref((\s.+?)>|(>.+?)</ref>)")
link_website = re.compile(r"\[.+?\]")
lang_template = re.compile(r"{{.+?\|.+?\|(.+?)}}")
br = re.compile(r"<.+?>")
space = re.compile(r"{{0}}")
Verwenden Sie den Inhalt der Vorlage, um die URL des Flaggenbilds abzurufen. (Hinweis: MediaWiki API imageinfo .2F_ii) kann aufgerufen werden, um den Dateiverweis in eine URL zu konvertieren)
Es scheint, dass Sie "https: // commons.wikimedia.org / w / api.php" mit verschiedenen Parametern (Dateiname usw.) anfordern sollten. Wenn Sie "Media Wiki API Image Info" usw. googeln, werden die Parameter angezeigt. Sie können "urllib" verwenden, um die API mit dem Python-Standardmodul aufzurufen. In der Dokumentation Verwendungsbeispiele heißt es: "Im Folgenden finden Sie eine Beispielsitzung zum Abrufen einer URL mit Parametern mithilfe der GET-Methode. Sie können dies tun, indem Sie sich den Teil "is:" ansehen.
Unten finden Sie ein Beispiel für die Antwort.
q29.py
import json
import sys
from urllib import request, parse
import re
baseinf = json.loads(sys.stdin.read())
url = 'https://commons.wikimedia.org/w/api.php'
params = {'action': 'query', 'prop': 'imageinfo', 'iiprop': 'url',
'format': 'json', 'titles': f'File:{baseinf["Flaggenbild"]}'}
req = request.Request(f'{url}?{parse.urlencode(params)}')
with request.urlopen(req) as res:
body = res.read()
# print(body['query']['pages']['347935']['imageinfo'][0]['url'])
print(re.search(r'"url":"(.+?)"', body.decode()).group(1))
!python q29.py < uk_baseinf.json
https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg
Da die zurückgegebene JSON-Datei kompliziert ist, ist es praktischer, nach dem URL-ähnlichen Teil zu suchen. Aus irgendeinem Grund war body
eine Byte-Zeichenfolge, daher funktionierte es nur, wenn ich es dekodierte.
re
json
str.startswith()
dict.items()
urllib
Persönlich war dieses Kapitel schmerzhaft. Ist es wie NLP vom nächsten Mal?
Recommended Posts