[Chapitre 3] Introduction à Python avec 100 coups de traitement du langage

Cet article est une suite de mon livre Introduction à Python avec 100 Knocking Language Processing. Je vais vous expliquer 100 coups Chapitre 3.

Ce chapitre utilise des expressions régulières. En Python, il est géré par le module re. Pour utiliser ce module, il est nécessaire de comprendre non seulement l'expression régulière elle-même, mais aussi la méthode et l'objet de correspondance, c'est donc assez difficile. Je ne pense plus que ce soit une entrée de gamme. Je n'avais pas l'impression de pouvoir écrire un meilleur commentaire que le Tutoriel officiel, alors veuillez le lire.

Cependant, les expressions canoniques Python sont lentes, j'essaye donc de les éviter autant que possible.

Pour le moment, téléchargez le fichier de manière appropriée. * Ce fichier est distribué sous la licence non portable Creative Commons Attribution-Inheritance 3.0. *

$ wget https://nlp100.github.io/data/jawiki-country.json.gz

Selon l'énoncé du problème, les informations d'un article par ligne sont stockées au format JSON. Le format JSON est une simple exportation de tableaux et de dictionnaires, et de nombreux langages de programmation prennent en charge ce format. Cependant, le format de tout ce fichier est appelé JSONL (JSON Lines). Jetez un œil au contenu du fichier avec $ gunzip -c jawiki-country.json.gz | less etc. (Vous pouvez le voir directement avec less).

json Python dispose également d'une bibliothèque pour gérer facilement ce JSON. Son nom est également json. Ceci est un exemple apporté de Document, mais il transforme une chaîne json en un objet Python comme celui-ci, et vice versa. C'est très simple à faire.

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]}

Comme c'était difficile à comprendre, j'ai également affiché le nom du type avec type (). Au fait, «s» in »se charge» et «dumps» signifie «chaîne» au lieu de 3 unités.

20. Lecture des données JSON

Lisez le fichier JSON de l'article Wikipedia et affichez le texte de l'article sur "UK". Dans les problèmes 21-29, exécutez sur le texte de l'article extrait ici.

Le fichier téléchargé est au format gz, mais je ne veux pas l'étendre autant que possible. Il est préférable de le lire avec le module gzip de Python, ou de sortir le résultat de l'expansion en standard avec la commande Unix et de le connecter avec un tube.

Voici un exemple de réponse.

q20.py


import json
import sys


for line in sys.stdin:
    wiki_dict = json.loads(line)
    if wiki_dict['title'] == 'Angleterre':
        print(wiki_dict.get('text'))

$ gunzip -c jawiki-country.json.gz | python q20.py > uk.txt
$ head -n5 uk.txt
{{redirect|UK}}
 {{redirect|Royaume-Uni|Pays honorables au printemps et à l'automne|Anglais(Printemps et automne)}}
 {{Otheruses|pays européen|Cuisine locale des préfectures de Nagasaki et Kumamoto|Igirisu}}

{{Informations de base sur le pays | Abréviation = Royaume-Uni

Je peux obtenir des redirections et des articles avec le même nom, mais il ne devrait y avoir aucun problème.

21. Extraire les lignes contenant les noms des catégories

Extrayez la ligne qui déclare le nom de la catégorie dans l'article.

Consultez la Wikipédia Référence rapide du balisage et le contenu du fichier réel Pensons-y.

Il semble suffisant d'extraire les lignes commençant par '[[Category'. str.startswith (prefix) retournera la valeur de vérité indiquant si la chaîne commence par prefix.

Voici un exemple de réponse.

q21.py


import sys


for line in sys.stdin:
    if line.startswith('[[Category'):
        print(line.rstrip())

(Je me souviens que la version 2015 était un mélange de minuscules [[categorys, mais c'est parti dans la version 2020 ...)

22. Extraction du nom de la catégorie

Extraire les noms des catégories d'articles (par nom, pas ligne par ligne).

Ce sera comme ça si vous vous coupez les mains.

q22.py


import sys


for line in sys.stdin:
    print(line.lstrip("[Category:").rstrip("|*]\n"))

$ python q21.py < uk.txt | python q22.py

Angleterre Pays membres du Royaume-Uni Royaume du Royaume-Uni Pays membres du G8 États membres de l'Union européenne | Ancien Nation marine Pays souverain existant Pays insulaire Une nation / territoire créé en 1801

23. Structure de la section

Affichez les noms de sections et leurs niveaux contenus dans l'article (par exemple, 1 si "== nom de section ==").

Remplacez == country name == par country name 1. Vous pouvez compter le sub dans la chaîne avec str.count (sub).

Voici un exemple de réponse qui n'utilise pas d'expressions régulières.

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)

24. Extraction des références de fichiers

Extrayez tous les fichiers multimédias référencés dans l'article.

Toutes les éditions 2020Fichier:Battle of Waterloo 1815.PNG|Il a la forme de ceci.|Utilisez des expressions régulières, en notant que vous souhaitez les supprimer et qu'il peut y en avoir plusieurs sur une ligne. Le test d'expressions régulières est facile avec les outils de vérification en ligne.

Voici un exemple de réponse.

q24.py


import re
import sys

pat = re.compile(r'(Fichier:)(?P<filename>.+?)\|')
for line in sys.stdin:
    for match in pat.finditer(line):
        print(match.group('filename'))

.+?\|Dans "Après le moins de répétitions possible de n'importe quel personnage|"Cela signifie que. Lors de l'examen de plusieurs matchsfinditer()Est pratique. S'il n'y a pas de correspondance, en premier lieuforLa phrase ne tourne pas.

Le même résultat peut être obtenu même si l'argument de «groupe» est 2.

25. Extraction de modèles

Extraire les noms de champs et les valeurs du modèle "informations de base" inclus dans l'article et les stocker sous forme d'objet dictionnaire.

Il est difficile de gérer les champs qui sont cassés dans le modèle.

{{Informations de base Pays
|Nom abrégé=Angleterre
|Nom du pays japonais=Royaume-Uni de Grande-Bretagne et d'Irlande du Nord
|Nom officiel du pays= {{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>Nom officiel du pays autre que l'anglais:<br/>
*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[Gaélique écossais]])<br/>
*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[Pays de Galles]])<br/>

Voici un exemple de réponse.

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('{{Informations de base'):
            isbaseinf = True


if __name__ == '__main__':
    main()

!python q25.py < uk.txt > uk_baseinf.json

S'il s'étend sur plusieurs lignes, il est traité en les concaténant.

Je l'écrirai une fois dans json car le code du prochain problème sera compliqué. A ce moment, les caractères seront déformés sauf si ʻensure_ascii = False`.

26. Suppression du balisage en surbrillance

Au moment du traitement> 25, supprimez le balisage d'accentuation MediaWiki (tout accent faible, accentuation et accentuation forte) de la valeur du modèle et convertissez-le en texte (Référence: [Markup Quick Reference](http: // ja. wikipedia.org/wiki/Help:% E6% 97% A9% E8% A6% 8B% E8% A1% A8)).

Si `` '' apparaît 2, 3 ou 5 fois de suite, supprimez-le. En termes d'expression régulière, cela ressemble à r '{2,5}. +?' {2,5}, mais c'est difficile de le faire sérieusement. Comme d'habitude, si vous le faites sans utiliser d'expressions régulières, cela ressemblera à ceci.

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()

La procédure consiste à lire le fichier json créé dans la question précédente à partir de l'entrée standard et à modifier la valeur de l'objet dictionnaire. dict.items () est un itérateur qui renvoie une série de paires (clé, valeur) dans le dictionnaire. Souvenons-nous-en.

Si vous voulez utiliser dans une chaîne littérale, vous devez échapper ou entourer l'extérieur avec . Pour rendre la même chaîne contiguë, vous pouvez la multiplier par un multiple entier. Et split ()` J'essaye de supprimer «» et de juger si le nombre d'éléments dans la liste retournée est impair afin de ne pas supprimer des «» irréguliers tels que «a» ». Il est calculé par «%», mais il peut être laissé tel quel même lorsque le quotient est égal à 0, donc en utilisant la fonction intégrée «divmod ()», le quotient et le reste sont calculés en même temps.

L'expression conditionnelle «A et B» est nouvelle pour moi, mais vous pouvez la voir en la regardant. La même chose est vraie pour «ou». Ce qui est important, c'est sa stratégie d'évaluation. Si «A et B» s'avère être «A == False», l'évaluation de l'expression se termine sans évaluer «B». Par conséquent, il est plus efficace de rendre "A" plus susceptible d'être "Faux" que "B". De même, ʻA ou B n'évalue pas B s'il s'avère être ʻA == True, alors écrivez une expression dans ʻA qui est plus susceptible d'être True`.

27. Suppression des liens internes

En plus du traitement 26, supprimez le balisage de lien interne de MediaWiki de la valeur du modèle et convertissez-le en texte (Référence: [Markup Quick Reference](https://ja.wikipedia.org/wiki/Help :) % E6% 97% A9% E8% A6% 8B% E8% A1% A8)).

Puisqu'il y a 3 modèles, nous utiliserons des expressions régulières.

q27.py


"""
[[Le titre de l'article]]
[[Le titre de l'article|Caractère d'affichage]]
[[Le titre de l'article#Nom de la section|Caractère d'affichage]] 
"""
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"""
        \[\[        # [[
        ([^|]+\|)*  #Le titre de l'article|Pas ou répété
        ([^]]+)     #Remplacez la partie qui correspond au caractère d'affichage pat par celle-ci
        \]\]        # ]]
    """, re.VERBOSE)
    for key, value in dic.items():
        value = pat.sub(r'\2', value)
        dic[key] = value
    return dic

if __name__ == '__main__':
    main()

Après avoir traité la question précédente, c'est un flux pour changer à nouveau la valeur du dictionnaire.

Vous pouvez écrire une chaîne littérale qui s'étend sur plusieurs lignes en la mettant entre guillemets triples. De plus, avec re.VERBOSE, les espaces, les sauts de ligne et les commentaires sont ignorés dans l'expression régulière, mais c'est toujours difficile à voir ...

La partie de pat.sub (r '\ 2', valeur) signifie remplacer la partie de valeur qui correspond à pat pargroupe (2)de l'objet de correspondance. ..

28. Suppression du balisage MediaWiki

En plus du traitement de> 27, supprimez autant que possible le balisage MediaWiki de la valeur du modèle et formatez les informations de base du pays.

Vous pouvez le faire avec Pandoc et pypandoc ... Si vous faites de votre mieux avec les expressions régulières, vous devez supprimer le balisage en surbrillance, les liens internes, les références de fichier, les liens externes, <ref>, <br />, {{0}}, uniquement les expressions régulières. Je vais le mettre ...

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"\[\[Fichier:.+?\|.+?\|(.+?)\]\]")
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}}")

29. Obtenez l'URL de l'image du drapeau

Utilisez le contenu du modèle pour obtenir l'URL de l'image du drapeau. (Indice: MediaWiki API imageinfo .2F_ii) peut être appelée pour convertir la référence de fichier en URL)

Il semble que vous devriez demander https: // commons.wikimedia.org / w / api.php avec divers paramètres (nom de fichier, etc.). Si vous google "info image de l'api du wiki multimédia" etc., les paramètres seront affichés. Vous pouvez utiliser ʻurllib` pour accéder à l'API avec le module standard Python. Dans la documentation Exemples d'utilisation, "Ce qui suit est un exemple de session pour utiliser la méthode GET pour obtenir une URL contenant des paramètres. Vous pouvez le faire en regardant la partie "est:".

Voici un exemple de réponse.

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["Image du drapeau"]}'}

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

Étant donné que le fichier JSON renvoyé est compliqué, il est plus pratique de rechercher la partie de type URL. Pour une raison quelconque, body était une chaîne d'octets, donc cela ne fonctionnait que si je le décodais.

Résumé

Vient ensuite le chapitre 4

Personnellement, ce chapitre a été douloureux. Est-ce que c'est comme la PNL de la prochaine fois?

Chapitre suivant

Recommended Posts

[Chapitre 5] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 3] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 2] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 4] Introduction à Python avec 100 coups de traitement du langage
[Chapitre 6] Introduction à scicit-learn avec 100 coups de traitement du langage
100 traitements de langage avec Python
100 traitements de langage avec Python (chapitre 3)
100 traitements de langage avec Python (chapitre 2, partie 2)
100 traitements de langage avec Python (chapitre 2, partie 1)
100 coups de traitement du langage ~ Chapitre 1
Introduction au langage Python
Le traitement de 100 langues frappe le chapitre 2 (10 ~ 19)
Démarrer avec Python avec 100 coups sur le traitement du langage
100 coups de traitement du langage avec Python 2015
100 Language Processing Knock Chapitre 2 (Python)
Réhabilitation des compétences Python et PNL à partir de "100 Language Processing Knock 2015" (Chapitre 1)
Introduction au traitement parallèle distribué Python par Ray
J'ai essayé de résoudre la version 2020 de 100 problèmes de traitement du langage [Chapitre 3: Expressions régulières 20 à 24]
J'ai essayé de résoudre la version 2020 de 100 coups de traitement de langue [Chapitre 1: Mouvement préparatoire 00-04]
J'ai essayé de résoudre la version 2020 de 100 traitements linguistiques [Chapitre 1: Mouvement préparatoire 05-09]
[Traitement du langage 100 coups 2020] Chapitre 3: Expressions régulières
100 Language Processing Knock Chapitre 1 en Python
100 coups de traitement du langage 2020: Chapitre 4 (analyse morphologique)
[Traitement du langage 100 coups 2020] Chapitre 5: Analyse des dépendances
[Introduction à Python3 Jour 13] Chapitre 7 Chaînes de caractères (7.1-7.1.1.1)
Introduction à Protobuf-c (langage C ⇔ Python)
[Traitement du langage 100 coups 2020] Chapitre 1: Mouvement préparatoire
Traitement d'image avec la binarisation Python 100 knocks # 3
[Traitement du langage 100 coups 2020] Chapitre 7: Vecteur Word
10 fonctions du "langage avec batterie" python
100 Language Processing Knock 2020: Chapitre 3 (expression régulière)
[Traitement du langage 100 coups 2020] Chapitre 8: Réseau neuronal
[Traitement du langage 100 coups 2020] Chapitre 2: Commandes UNIX
[Traitement du langage 100 coups 2020] Chapitre 9: RNN, CNN
100 traitement d'image par Python Knock # 2 Échelle de gris
100 Language Processing Knock Chapitre 1 par Python
[Traitement du langage 100 coups 2020] Chapitre 4: Analyse morphologique
[Introduction à Python3 Day 21] Chapitre 10 Système (10.1 à 10.5)
Traitement du langage 100 knocks-48: Extraction du chemin du nez à la racine
[Raspi4; Introduction au son] Enregistrement stable de l'entrée sonore avec python ♪
Réhabilitation des compétences Python et PNL à partir de «Knock 100 Language Processing 2015» (chapitre 2 deuxième semestre)
Réhabilitation des compétences Python et PNL à partir de "100 Language Processing Knock 2015" (Chapitre 2 premier semestre)
100 coups de traitement linguistique (2020): 40
Bases du traitement d'images binarisées par Python
100 coups de traitement linguistique (2020): 32
J'ai fait 100 traitements linguistiques Knock 2020 avec GiNZA v3.1 Chapitre 4
100 coups de traitement linguistique (2020): 35
100 coups de traitement linguistique (2020): 47
100 coups de traitement linguistique (2020): 39
[Introduction à Python3, jour 17] Chapitre 8 Destinations de données (8.1-8.2.5)
Chapitre 4 Résumé de l'introduction aux modèles de conception appris en langage Java
100 coups de traitement linguistique (2020): 22
100 traitement de langue knock-22: Extraction du nom de la catégorie
100 coups de traitement linguistique (2020): 26
100 coups de traitement linguistique (2020): 34
[Introduction à Python3, jour 17] Chapitre 8 Destinations de données (8.3-8.3.6.1)
100 traitement d'image avec Python Knock # 8 Max Pooling
100 coups de traitement linguistique (2020): 42
Introduction au remplissage d'image Python Remplissage d'image à l'aide d'ImageDataGenerator