[PYTHON] 100 Traitement du langage Knock Expressions régulières apprises au chapitre 3

introduction

Je résous 100 coups sur le traitement du langage lors d'une session d'étude centrée sur les membres de l'entreprise, mais le code de réponse et la solution Ceci est un résumé des astuces que j'ai trouvées utiles dans le processus. La plupart du contenu a été étudié et vérifié par moi-même, mais il contient également des informations partagées par d'autres membres du groupe d'étude.

Cette fois, c'est une expression régulière, mais il y a eu une réponse du contenu de base aux problèmes difficiles et difficiles.

Je n'ai pas eu l'occasion d'apprendre les expressions régulières sérieusement jusqu'à présent, j'ai donc examiné les connaissances de base à l'avance, mais Document Python original /re.html) et les pages WWW Creators sont faciles à lire et à organiser, ce qui m'a aidé. Certains des documents de type tutoriel ont été écrits par le maître Ruby Mr. Ito, ce qui peut être utile lorsque vous êtes bloqué.

séries

environnement

code

Prétraitement

Mettez jawiki-country.json.gz dans le même répertoire que le fichier ipynb (ou Python)

!gzip -d jawiki-country.json.gz

Ensuite, vous pouvez décompresser le zip.

20. Lecture des données JSON

import json

def load_uk():
    with open('jawiki-country.json') as file:
        for item in file:
            d = json.loads(item)

            if d['title'] == 'Angleterre':
                return d['text']

print(load_uk())

résultat


{{redirect|UK}}
{{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/>
...

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

import re

def extract_categ_lines():
    return re.findall(r'.*Category.*', load_uk())

print(*extract_categ_lines())

résultat


[[Category:Angleterre|*]] [[Category:Royaume du Royaume-Uni|*]] [[Category:Pays membres du G8]] [[Category:Pays membres de l'Union européenne]] [[Category:Nation marine]] [[Category:Pays souverain]] [[Category:Pays insulaire|Kureito Furiten]] [[Category:État / région créé en 1801]]

Puisque l'énoncé du problème contient le mot "extraire les lignes", j'ai envie d'utiliser split () pour séparer la valeur de retour de load_uk () pour chaque ligne, mais un tel traitement est essentiel. N'est pas. . Représente" n'importe quel caractère sauf les sauts de ligne ", donc si vous écrivez comme ci-dessus, vous ne pouvez récupérer que la ligne contenant la chaîne de caractères Category.

22. Extraction du nom de la catégorie

def extract_categs():
    return re.findall(r'.*Category:(.*?)\]', load_uk())
    
print(*extract_categs())

résultat


Angleterre|*Royaume du Royaume-Uni|*Pays membres du G8 Pays membres de l'Union européenne Pays marins Pays souverains Pays insulaires|État / région de Kureito Furiten fondé en 1801

Entourez () pour capturer la chaîne immédiatement après Category:. Cependant, j'ai ajouté ? Après * pour le rendre non gourmand (spécifiez la correspondance la plus courte) afin que le ] après ne soit pas pris ensemble.

23. Structure de la section

def extract_sects():
    tuples = re.findall(r'(={2,})\s*([^\s=]*).*', load_uk())

    sects = []
    for t in tuples:
        if t[0] == '==':
            sects.append([t[1], 1])
        elif t[0] == '===':
            sects.append([t[1], 2])
        elif t[0] == '====':
            sects.append([t[1], 3])

    return sects

print(*extract_sects())

résultat


['Nom du pays', 1] ['histoire', 1] ['La géographie', 1] ['climat', 2] ['Politique', 1] ['Diplomatie et militaire', 1] ['Division de l'administration locale', 1] ['Grandes villes', 2] ['Science et technologie', 1] ['Économie', 1] ['Exploitation minière', 2] ['Agriculture', 2] ['Commerce', 2] ['devise', 2] ['Compagnie', 2] ['trafic', 1] ['route', 2] ['Chemin de fer', 2] ['livraison', 2] ['Aviation', 2] ['la communication', 1] ['Gens', 1] ['Langue', 2] ['religion', 2] ['mariage', 2] ['éducation', 2] ['culture', 1] ['食culture', 2] ['Littérature', 2] ['philosophie', 2] ['musiques', 2] ['イギリスのポピュラーmusiques', 3] ['films', 2] ['la comédie', 2] ['fleur nationale', 2] ['héritage du monde', 2] ['Vacances', 2] ['Des sports', 1] ['Football', 2] ['Course de chevaux', 2] ['モーターDes sports', 2] ['note de bas de page', 1] ['Article connexe', 1] ['Lien externe', 1]

Puisque ^ \ s = signifie "tout caractère qui n'est ni vide ni = ",[^ \ s =] +signifie" un ou plusieurs caractères arbitraires qui ne sont ni vides ni=". Cela signifie «choses». Il s'agit du nom de la section, qui est la première valeur que vous souhaitez obtenir cette fois. En plus de cela, si vous placez = {2,} dans (), vous pouvez obtenir "deux ou plus` = ʻen ligne".

Pour chaque correspondance, un taple contenant les deux valeurs ci-dessus est retourné, donc je l'ai utilisé pour créer la valeur de retour avec l'instruction for. Je n'ai pas à m'inquiéter du format de la valeur de retour car il n'est pas spécifié, mais je l'ai choisi comme un tableau de tableaux.

En passant, dans le code ci-dessus, nous préparons d'abord une liste appelée sects, y mettons des éléments, puis la retournons à la fin, mais l'utilisation de yield rend cela un peu plus concis. Peut être écrit.

def extract_sects_2():
    tuples = re.findall(r'(={2,})\s*([^\s=]+).*', load_uk())

    for t in tuples:
        if t[0] == '==':
            yield [t[1], 1]
        elif t[0] == '===':
            yield [t[1], 2]
        elif t[0] == '====':
            yield [t[1], 3]

print(*extract_sects_2())

Une fonction utilisant yield est appelée un générateur et renvoie un itérateur (itérateur du générateur) (pour plus de détails, voir documentation Python. Voir # term-generator)), il semble que l'itérateur puisse être développé avec * devant lui comme ci-dessus, ou converti en liste en le passant à list ().

24. Extraction des références de fichiers

def extract_media_files():
    return re.findall(r'(?:File|Fichier):(.+?)\|', load_uk())

extract_media_files()

résultat


['Royal Coat of Arms of the United Kingdom.svg',
 'Battle of Waterloo 1815.PNG',
 'The British Empire.png',
 'Uk topo en.jpg',
 'BenNevis2005.jpg',
 ...

Je dois utiliser () pour représenter " File ou file", mais je ne veux pas capturer cela, alors j'ai écrit ?: Immédiatement après (? ".

Au fait, la raison pour laquelle print () n'est pas utilisé dans la dernière ligne est que si vous renvoyez une liste etc. ici, Jupyter la formatera puis la sortira.

25. Extraction de modèles

def extract_template():
    data = re.search(r'\{\{Informations de base.*\n\}\}', load_uk(), re.DOTALL).group()
    tuples = re.findall(r'\n\|(.+?)\s=\s(.+?)(?:(?=\n\|)|(?=\}\}\n))', data, re.DOTALL)

    return dict(tuples)

extract_template()

résultat



{'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/>\n*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[Gaélique écossais]])<br/>\n*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[Pays de Galles]])<br/>\n*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}([[irlandais]])<br/>\n*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}([[Cornouailles]])<br/>\n*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}([[Écossais]])<br/>\n**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(アルスター・Écossais)</ref>',
 ...
 'Numéro de téléphone international': '44'}

Personnellement, c'était la question la plus difficile de ce chapitre. Cependant, j'ai appris le processus des difficultés, donc j'écrirai un peu plus sur le cœur du problème, re.findall (). Lorsque vous réfléchissez au type d'expression régulière à utiliser ici, probablement au début

re.findall(r'\n\|(.+)\s=\s(.+)\n\|', data)

Je pense qu'un code comme celui-ci me vient à l'esprit. Cependant, lorsque j'essaie de faire cela, je peux voir que la partie que je voulais prendre de manière égale, comme le nom du pays japonais '': la Grande-Bretagne et le Royaume-Uni d'Irlande du Nord '', n'est pas prise. La cause de ceci est

\n|Nom abrégé=Angleterre\n|Nom du pays japonais

Quand il y a une chaîne de caractères comme, si c'est l'expression régulière ci-dessus\n|Nom abrégé=Angleterre\n|Après un match, commencez à chercher le prochain matchjournéeC'est parce qu'il devient la chaîne de caractères aprèsdocumentSivousutilisezl'expressionci-dessus,l'expressionrégulièreci-dessusestjournéeDevantde\n|Nefonctionnepascaril"consomme").

Alors que faire\n|Il existe une méthode appelée "look-ahead" pour éviter la consommation de. En tant que code, l'expression régulière\n\|À(?=)Insérez-le et procédez comme suit.

re.findall(r'\n\|(.+)\s=\s(.+)(?=\n\|)', load_uk())

Si vous l'exécutez à nouveau avec ceci, vous devriez être en mesure d'obtenir correctement les lignes telles que «nom du pays japonais». Cependant, si vous regardez attentivement la chaîne de caractères obtenue ici, seule la première ligne expliquant le nom officiel du pays est incluse. Cela signifie que le . + Écrit dans le second () correspondra à "un ou plusieurs caractères arbitraires sauf le saut de ligne ( \ n). " En d'autres termes, il n'est pas possible de franchir les lignes.

Par conséquent, passez un module appelé re.DOTALL à findall (). Ensuite, . + Va chercher "un ou plusieurs caractères arbitraires", mais si vous laissez + gourmand, vous en aurez trop. Ajoutons un «?» À la fin.

re.findall(r'\n\|(.+?)\s=\s(.+?)(?=\n\|)', load_uk(), re.DOTALL)

Je pense que c'est à peu près OK, mais si vous regardez de près les résultats renvoyés, il y a un problème que vous obtenez trop à la fin. Par conséquent, regardez en avant la chaîne de caractères après le modèle et modifiez-la comme suit afin qu'elle corresponde même si c'est }} \ n.

re.findall(r'\n\|(.+?)\s=\s(.+?)(?:(?=\n\|)|(?=\}\}\n))', data, re.DOTALL)

Avec cela, j'ai finalement écrit le code qui satisfait la spécification de l'énoncé du problème, mais si je sens que j'ai emballé trop de choses dans une ligne, je peux utiliser re.complile () pour séparer les lignes comme suit. pense.

pattern = re.compile(r'\n\|(.+?)\s=\s(.+?)(?:(?=\n\|)|(?=\}\}\n))', re.DOTALL)
tuples = pattern.findall(data)

Si vous souhaitez insérer un saut de ligne dans la partie expression régulière, vous pouvez ajouter + re.MULTILINE après re.DOTALL.

26. Suppression du balisage en surbrillance

def remove_emphases():
    d = extract_template()
    return {key: re.sub(r'\'{2,5}', '', val) for key, val in d.items()}

remove_emphases()

résultat


{'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/>\n*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[Gaélique écossais]])<br/>\n*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[Pays de Galles]])<br/>\n*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}([[irlandais]])<br/>\n*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}([[Cornouailles]])<br/>\n*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}([[Écossais]])<br/>\n**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(アルスター・Écossais)</ref>',
 ...
 'Forme établie 4': 'Changement du nom de pays actuel "Grande-Bretagne et Royaume-Uni d'Irlande du Nord"',
 ...

Par rapport à 25, les expressions régulières sont un problème qui peut être résolu avec seulement des connaissances de base, mais il y a une mise en garde que si vous mettez un espace après «2», cela ne fonctionnera pas dans certains cas.

Je pense que la notation interne du dictionnaire est une notation propre à Python, mais au fur et à mesure que je m'y habitue, je peux l'écrire de manière concise, donc je l'utilise souvent personnellement.

27. Suppression des liens internes

def remove_links():
    d = remove_emphases()
    return {key: re.sub(r'\[\[.*?\|?(.+?)\]\]', r'\\1', val) for key, val in d.items()}

remove_links()

résultat


{'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/>\n*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}(Gaélique écossais)<br/>\n*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}(Pays de Galles)<br/>\n*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}(Irlandais)<br/>\n*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}(Cornouailles)<br/>\n*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}(Écossais)<br/>\n**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(Ulster écossais)</ref>',
 'Image du drapeau': 'Flag of the United Kingdom.svg',
 'Image de l'emblème national': 'Fichier:Royal Coat of Arms of the United Kingdom.svg|85px|Emblème national britannique',
 ...

Que veux-tu faire[[]]S'il y a une partie entourée par, retirez le contenu. Cependant, en elle|S'il y a|J'ai essayé de le résoudre en définissant «ne retirer que l'arrière de».|Je ne sais pas si ça va sortir ou pas, donc derrière?Est ajouté pour spécifier qu'il correspond à 0 ou 1 répétition.

28. Suppression du balisage MediaWiki

def remove_markups():
    d = remove_links()
    #Supprimer les liens externes
    d = {key: re.sub(r'\[http:.+?\s(.+?)\]', '\\1', val) for key, val in d.items()}
    #Supprimer ref (balise de début et balise de fin ensemble) et br
    d = {key: re.sub(r'</?(ref|br).*?>', '', val) for key, val in d.items()}
    return d

remove_markups()

résultat


{'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}}Nom officiel du pays autre que l'anglais:\n*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}(Gaélique écossais)\n*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}(Pays de Galles)\n*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}(Irlandais)\n*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}(Cornouailles)\n*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}(Écossais)\n**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(Ulster écossais)',
 'Image du drapeau': 'Flag of the United Kingdom.svg',
 ...
 'Valeur de la population': '63,181,775United Nations Department of Economic and Social Affairs>Population Division>Data>Population>Total Population',
 ...

{{lang|.+?|.+?}}Je pensais que de tels modèles devraient être supprimés,~~je suis fatigué~~Il ne figurait pas dans le tableau de référence rapide, je l'ai donc laissé tel quel cette fois.

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

import requests
import json

def get_flag_url():
    d = remove_markup()['Image du drapeau']
    
    url = 'https://www.mediawiki.org/w/api.php'
    params = {'action': 'query',
              'titles': f'File:{d}',
              'format': 'json',
              'prop': 'imageinfo',
              'iiprop': 'url'}
    res = requests.get(url, params)

    return res.json()['query']['pages']['-1']['imageinfo'][0]['url']

get_flag_url()

résultat


'https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg'

Un problème qui ne demande soudainement de connaître HTTP qu'à la fin. C'est un peu difficile à résoudre sans connaître la demande et la réponse. Si vous ne comprenez pas bien et que vous voulez le comprendre grossièrement, vous pouvez utiliser la vidéo ici, et si vous voulez en savoir un peu plus, [Document MDN](https: //) developer.mozilla.org/en/docs/Web/HTTP/Overview) peut être utile.

Dans ce problème, vous pouvez extraire l'URL de l'image du drapeau de la réponse renvoyée lorsque vous envoyez une requête GET à l'API MediaWiki avec Python, etc., mais pour cela, vous devez importer un module spécial.

Il semble que vous puissiez utiliser urllib.request si vous ne voulez pas vous soucier d'installer des packages externes, mais j'ai décidé d'utiliser des requêtes car je l'avais installé dans le passé. C'est un code plus simple, et je l'ai écrit parce qu'il est largement utilisé, y compris l'exemple sur la page ici de MediaWiki. Je pense que c'est facile.

À propos, les 7 lignes du milieu peuvent être écrites sur 2 lignes comme indiqué ci-dessous, mais dans ce cas, l'URL s'agrandira trop horizontalement, il est donc préférable de séparer les lignes comme décrit ci-dessus.

url = f'https://www.mediawiki.org/w/api.php?action=query&titles=File:{d}&format=json&prop=imageinfo&iiprop=url'    
res = requests.get(url)

Résumé

Les expressions régulières sont un outil qui est utilisé non seulement dans le traitement du langage mais aussi dans le développement Web, mais ce chapitre couvre un large éventail de sujets et j'ai senti que c'était un bon matériel pédagogique.

Comme mentionné ci-dessus, je l'ai écrit dans le but de créer un code précis et concis, mais si vous avez des erreurs, veuillez commenter.

Recommended Posts

100 Traitement du langage Knock Expressions régulières apprises au chapitre 3
100 Language Processing Knock 2020 Chapitre 3: Expressions régulières
[Traitement du langage 100 coups 2020] Chapitre 3: Expressions régulières
100 Language Processing Knock Chapitre 1 en Python
100 Traitement du langage Knock Chapitre 1
100 Language Processing Knock 2020 Chapitre 3
100 Language Processing Knock 2020 Chapitre 2
100 traitements du langage frappent l'analyse morphologique apprise au chapitre 4
100 Language Processing Knock Chapitre 1 (Python)
100 Language Processing Knock Chapitre 2 (Python)
100 traitements du langage naturel frappent Chapitre 3 Expressions régulières (première moitié)
100 traitements du langage naturel frappent Chapitre 3 Expressions régulières (seconde moitié)
100 Language Processing Knock 2020 Chapitre 2: Commandes UNIX
100 Language Processing Knock 2015 Chapitre 5 Analyse des dépendances (40-49)
100 traitements de langage avec Python
100 Language Processing Knock 2020 Chapitre 9: RNN, CNN
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 3
100 traitements de langage avec Python (chapitre 3)
100 Language Processing Knock: Chapitre 1 Mouvement préparatoire
100 Language Processing Knock 2020 Chapitre 6: Apprentissage automatique
100 Traitement du langage Knock Chapitre 4: Analyse morphologique
100 Language Processing Knock 2020 Chapitre 10: Traduction automatique (90-98)
100 Language Processing Knock 2020 Chapitre 5: Analyse des dépendances
100 Language Processing Knock 2020: Chapitre 3 (expression régulière)
100 Traitement du langage Knock 2020 Chapitre 7: Vecteur de mots
100 Language Processing Knock 2020 Chapitre 8: Neural Net
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 1
100 Language Processing Knock 2020 Chapitre 1: Mouvement préparatoire
100 Language Processing Knock Chapitre 1 par Python
100 Language Processing Knock 2015 Chapitre 4 Analyse morphologique (30-39)
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 2
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 4
100 coups de traitement linguistique (2020): 28
100 coups de traitement linguistique (2020): 38
100 traitement de la langue frapper 00 ~ 02
J'ai fait 100 traitements linguistiques Knock 2020 avec GiNZA v3.1 Chapitre 4
100 traitements de langage avec Python (chapitre 2, partie 2)
100 traitements de langage avec Python (chapitre 2, partie 1)
[Programmeur nouveau venu "100 language processing knock 2020"] Résoudre le chapitre 1
100 traitements linguistiques Knock 2020 [00 ~ 39 réponse]
100 langues de traitement knock 2020 [00-79 réponse]
100 traitements linguistiques Knock 2020 [00 ~ 69 réponse]
100 coups de traitement du langage amateur: 17
100 traitements linguistiques Knock 2020 [00 ~ 49 réponse]
100 Traitement du langage Knock-52: Stemming
100 coups de traitement du langage ~ Chapitre 1
J'ai essayé de résoudre 100 traitements linguistiques Knock version 2020 [Chapitre 3: Expressions régulières 25-29]
100 coups de langue amateur: 07
Le traitement de 100 langues frappe le chapitre 2 (10 ~ 19)
100 coups de traitement du langage amateur: 09
100 coups en traitement du langage amateur: 47
Traitement 100 langues knock-53: Tokenisation
100 coups de traitement du langage amateur: 97
100 traitements linguistiques Knock 2020 [00 ~ 59 réponse]
100 coups de traitement du langage amateur: 67
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]
Traitement du langage 100 knock-80 (remplacé par une expression régulière): formatage du corpus
100 Language Processing Knock: Chapitre 2 Principes de base des commandes UNIX (à l'aide de pandas)
[Programmer newcomer "100 language processing knock 2020"] Résoudre le chapitre 2 [Première moitié: 10 ~ 15]
100 coups de traitement du langage avec Python 2015
100 traitement du langage Knock-51: découpage de mots