How to extract the address data from a String in Python

Viewed 402

I am trying to extract relevant address info form an string and discard the garbage. So this:

al domicilio social de la Compañía, Avenida de Burgos, 109 - 28050 Madrid (Indicar Asesoría Jurídica – Protección de Datos) 

Should be:

Avenida de Burgos, 109 - 28050 Madrid

What i've done:

I am using stanza NER to find locations from text.

After that, I am using the indexes of the found entities to get the full address. For eg: If A Madrid (Spanish city) is found in text[120:128] i will extract the string text[60:101] to get the full address.

My current code is:

##
##STANZA NER FOR LOCATIONS
##
!pip install stanza
#Download the spanish model
import stanza
stanza.download('es') 
#create and run the ner tagger
nlp = stanza.Pipeline(lang='es', processors='tokenize,ner')
text = 'al domicilio social de la Compañía, Avenida de Burgos, 109 - 28050 Madrid (Indicar Asesoría Jurídica – Protección de Datos) '
doc = nlp(text)

#print results of NER tagger
print([ent for ent in doc.ents if ent.type=="LOC"], sep='\n')
print(*[text[int(ent.start_char)-60:int(ent.end_char)+15] for ent in doc.ents if ent.type=="LOC"], sep='\n')

After this, in this particular case, which should be reproducible. I get the next address.

cilio social de la Compañía, Avenida de Burgos, 109 - 28050 Madrid (Indicar Aseso

Which contains extra "garbage" info --> " cilio social de la Compañía," and "(Indicar Aseso"

In the next part of the process,I am using the libpostal library to parse the address as it follows:

!pip install postal
from postal.parser import parse_address
parse_address('Avenida de Burgos, 109 - 28050 Madrid')

Which works reliably in most cases, but only with clean addresses.

  [('avenida de burgos', 'road'),
 ('109', 'house_number'),
 ('28050', 'postcode'),
 ('madrid', 'city')]

So, to sum up, I am searching from another tecnique apart from regex to help me discard garbage info from addresses apart from regex. (Libraries which do this if they exist or a new NLP approach ... ) Thanks

1 Answers

For US address extraction from bulk text:

For US addresses in bulks of text I have pretty good luck, though not perfect with the below regex. It wont work on many of the oddity type addresses and only captures first 5 of the zip.

Explanation:

  • ([0-9]{1,6}) - string of 1-5 digits to start off
  • (.{5,75}) - Any character 5-75 times. I looked at the addresses I was interested in and the vast vast majority were over 5 and under 60 characters for the address line 1, address 2 and city.
  • (BIG LIST OF AMERICAN STATES AND ABBERVIATIONS) - This is to match on states. Assumes state names will be Title Case.
  • .{1,2} - designed to accommodate many permutations of ,/s or just /s between the state and the zip
  • ([0-9]{5}) - captures first 5 of the zip.

text = "is an individual maintaining a residence at 175 Fox Meadow, Orchard Park, NY 14127. 2. other,"

address_regex = r"([0-9]{1,6})(.{5,75}?)((?:Ala(?:(?:bam|sk)a)|American Samoa|Arizona|Arkansas|(?:^(?!Baja )California)|Colorado|Connecticut|Delaware|District of Columbia|Florida|Georgia|Guam|Hawaii|Idaho|Illinois|Indiana|Iowa|Kansas|Kentucky|Louisiana|Maine|Maryland|Massachusetts|Michigan|Minnesota|Miss(?:(?:issipp|our)i)|Montana|Nebraska|Nevada|New (?:Hampshire|Jersey|Mexico|York)|North (?:(?:Carolin|Dakot)a)|Ohio|Oklahoma|Oregon|Pennsylvania|Puerto Rico|Rhode Island|South (?:(?:Carolin|Dakot)a)|Tennessee|Texas|Utah|Vermont|Virgin(?:ia| Island(s?))|Washington|West Virginia|Wisconsin|Wyoming|A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])).{1,2}([0-9]{5})"

addresses = re.findall(address_regex, text)

addresses is then: [('175', ' Fox Meadow, Orchard Park, ', 'NY', '', '14127')]

You can combine these and remove spaces like so:

for address in addresses:
    out_address = " ".join(address)
    out_address = " ".join(out_address.split())

To then break this into a proper line 1, line 2 etc. I suggest using an address validation API like Google or Lob. These can take a string and break it into parts. There are also some python solutions for this like usaddress

For outside the US

To port this to other locations suggest considering how this could be adapted to your region. If you have a finite number of states and a similar structure, try looking for someone who has already built the "state" regex for your country.

Related