2016-12-15 2 views
0

Je suis en train d'analyser deux types de chaînes d'adresse d'une ligne:Python regex - analyse des adresses

Flat XXX, XXX <Building name>, <City/town>, <State> <Postcode> 

DDD <Generic place name>, <Road name> road, <City/town>, <State> 

à l'aide en utilisant l'expression rationnelle suivante

re.search(r'(Flat \w+)?\W*(.+)\W*([a-zA-Z]{1,2}\d+\s+\d+[a-zA-Z]{1,2})? 

Ici XXX est une chaîne de caractères alphanumériques, et DDD est un nombre. Je m'attends à ce que le groupe 1 soit Flat XXX si l'adresse est du premier type ou None sinon, le groupe 2 sera XXX <Building name>, <City/town>, <State> si l'adresse est du premier type, ou <Road name> road, <City/town>, <State> s'il s'agit du deuxième type, et le groupe 3 est le code postal si l'adresse est du premier type ou None sinon. Le code postal est un code postal au Royaume-Uni pour lequel mon regex (pas complètement précis mais surtout correct pour mon but) est [a-zA-Z]{1,2}\d+\s+\d+[a-zA-Z]{1,2}. Case doit être ignorée et il ne peut y avoir aucune virgule entre Flat XXX (si elle existe) et <Building name>, et il peut y avoir une virgule entre la ville et le code postal (s'il existe).

>>> address1 = 'Flat 29, Victoria House, Redwood Lane, Richmond, London SW14 9XY' 
>>> re.search(r'(Flat \w+)?\W*(.+)\W*([a-zA-Z]{1,2}\d+\s+\d+[a-zA-Z]{1,2})?', address1, re.I).groups() 
>>> ('Flat 29', 'Victoria House, Redwood Lane, Richmond, London SW14 9XY', None) 
>>> address2 = '91 Fleet, Major Road, Fleet, Hampshire' 
>>> re.search(r'(Flat \w+)?\W*(.+)\W*([a-zA-Z]{1,2}\d+\s+\d+[a-zA-Z]{1,2})?', address2, re.I).groups() 
>>> (None, '91 Fleet, Major Road, Fleet, Hampshire', None) 

Je ne sais pas ce qui va mal, mais je pense que le groupe est plus ..\W*(.+)\W*.. milieu ou moins tout capture.

+0

Oui, c'est: https://regex101.com/r/uC6fiZ/1 –

+0

Qu'avez-vous finalement besoin d'obtenir des adresses? – asongtoruin

+0

Avez-vous considéré et essayé la version non gourmande: '.. \ W * (. +?) \ W * ..'? – Evert

Répondre

0

Il est pas particulièrement élégant, mais voici un peu d'une solution de contournement (en supposant que <State> ne contient pas de chiffres):

import re 
addresses = ['Flat 29, Victoria House, Redwood Lane, Richmond, London SW14 9XY', 
      '91 Fleet, Major Road, Fleet, Hampshire'] 

regexp = re.compile(r'(Flat \w+)?[,\s]*(.*)\s([a-zA-Z]{1,2}\d+\s?+\d+[a-zA-Z]{1,2}|\D*)$', re.I) 

for address in addresses: 
    sep_addr = list(re.search(regexp, address).groups()) 
    if not any(x.isdigit() for x in sep_addr[2]): 
     sep_addr[1] += ' ' + sep_addr[2] 
     sep_addr[2] = None 
    print sep_addr 

Nous fixons groupe 2 pour être soit le code postal ou le dernier mot dans la adresse fournie. Puis, en vérifiant s'il y a des chiffres dans le résultat de notre deuxième groupe, nous savons s'il s'agit d'un code postal ou non. Si ce n'est pas le cas, nous ajoutons au groupe 1 pour indiquer la partie de l'adresse complète et définissons le groupe 2 sur None. Ce retour:

['Flat 29', 'Victoria House, Redwood Lane, Richmond, London', 'SW14 9XY'] 
[None, '91 Fleet, Major Road, Fleet, Hampshire', None] 

EDIT: Ajout d'une option à l'espace au milieu du code postal, pour assurer moins d'espace-codes postaux sont toujours adaptés.