Andrew
Andrew

Reputation: 3999

Separate city and state in string?

A string, citystate, could be formatted like:

"Greenwich, CT"
"Greenwich,CT"
"Greenwich CT"

How can I split the string, citystate, into two separate strings, city and state (using Python)?

(such that city == Greenwich and state == CT)

Thanks for the help!

Upvotes: 1

Views: 1390

Answers (4)

John Machin
John Machin

Reputation: 82934

Making some assumptions:

(1) A state code is two characters, and you will verify the split results by looking up a table of state codes

(2) Your input data has already been converted to unicode (Python 2.X) or str (Python 3.x)

(3) A much wider range of possible data-entry stuffups and script-kiddie stuffups could have happened to your data.

Code:

tests = [
    u"Foo YZ", u"Foo YZ\n", u"Foo\xa0YZ", u"Foo  YZ",
    u"Foo, YZ", u"Foo, YZ\n", u"Foo,\xa0YZ",
    u"Foo,YZ", u"Foo,YZ\n", u"Foo,,YZ",
    u"FooYZ", u"   Foo \t,\xa0   YZ \n",
    ]

import re

def machin(strg):
    strg = strg.strip()
    state = strg[-2:]
    city = u" ".join(strg[:-2].split()) # normalise whitespace
    city = city.rstrip(", ")
    return city, state

def kettler(strg):
    split_loc = re.split(r' ?,? ?', strg)
    city = ' '.join(split_loc[:-1]) # Everything up to last element joined by space
    state = split_loc[-1]
    return city, state

def bothwell(strg):
    # split on last comma
    res = strg.rsplit(',', 1)
    if len(res)==2:
        return res[0].strip(), res[1].strip()
    # otherwise split on last non-trailing whitespace
    res = strg.rsplit(None, 1)
    if len(res)==2:
        return res[0].lstrip(), res[1]
    # otherwise split failed
    # raise ValueError("Could not split {0} into city, state".format(s))
    return None, None

def paulger_v2(strg):
    return strg[:-3].strip(", "), strg[-2:]


funcs = (kettler, bothwell, paulger_v2, machin)

for func in funcs:
    print "\n===", func.__name__, "==="
    nok = 0
    for test in tests:
        city, state = func(test)
        ok = city == u"Foo" and state == u"YZ"; nok += ok
        print [ok, test, city, state]
        test = test.replace(u"Foo", u"Foo  Baa")
        city, state = func(test)
        ok = city == u"Foo Baa" and state == u"YZ"; nok += ok
        print [ok, test, city, state]
    print "\n+++ %s: %d OK +++" % (func.__name__, nok)

Output:

=== kettler ===
[True, u'Foo YZ', u'Foo', u'YZ']
[True, u'Foo  Baa YZ', u'Foo Baa', u'YZ']
[False, u'Foo YZ\n', u'Foo', u'YZ\n']
[False, u'Foo  Baa YZ\n', u'Foo Baa', u'YZ\n']
[False, u'Foo\xa0YZ', '', u'Foo\xa0YZ']
[False, u'Foo  Baa\xa0YZ', u'Foo', u'Baa\xa0YZ']
[True, u'Foo  YZ', u'Foo', u'YZ']
[True, u'Foo  Baa  YZ', u'Foo Baa', u'YZ']
[True, u'Foo, YZ', u'Foo', u'YZ']
[True, u'Foo  Baa, YZ', u'Foo Baa', u'YZ']
[False, u'Foo, YZ\n', u'Foo', u'YZ\n']
[False, u'Foo  Baa, YZ\n', u'Foo Baa', u'YZ\n']
[False, u'Foo,\xa0YZ', u'Foo', u'\xa0YZ']
[False, u'Foo  Baa,\xa0YZ', u'Foo Baa', u'\xa0YZ']
[True, u'Foo,YZ', u'Foo', u'YZ']
[True, u'Foo  Baa,YZ', u'Foo Baa', u'YZ']
[False, u'Foo,YZ\n', u'Foo', u'YZ\n']
[False, u'Foo  Baa,YZ\n', u'Foo Baa', u'YZ\n']
[False, u'Foo,,YZ', u'Foo ', u'YZ']
[False, u'Foo  Baa,,YZ', u'Foo Baa ', u'YZ']
[False, u'FooYZ', '', u'FooYZ']
[False, u'Foo  BaaYZ', u'Foo', u'BaaYZ']
[False, u'   Foo \t,\xa0   YZ \n', u'  Foo \t \xa0  YZ', u'\n']
[False, u'   Foo  Baa \t,\xa0   YZ \n', u'  Foo Baa \t \xa0  YZ', u'\n']

+++ kettler: 8 OK +++

=== bothwell ===
[True, u'Foo YZ', u'Foo', u'YZ']
[False, u'Foo  Baa YZ', u'Foo  Baa', u'YZ']
[True, u'Foo YZ\n', u'Foo', u'YZ']
[False, u'Foo  Baa YZ\n', u'Foo  Baa', u'YZ']
[True, u'Foo\xa0YZ', u'Foo', u'YZ']
[False, u'Foo  Baa\xa0YZ', u'Foo  Baa', u'YZ']
[True, u'Foo  YZ', u'Foo', u'YZ']
[False, u'Foo  Baa  YZ', u'Foo  Baa', u'YZ']
[True, u'Foo, YZ', u'Foo', u'YZ']
[False, u'Foo  Baa, YZ', u'Foo  Baa', u'YZ']
[True, u'Foo, YZ\n', u'Foo', u'YZ']
[False, u'Foo  Baa, YZ\n', u'Foo  Baa', u'YZ']
[True, u'Foo,\xa0YZ', u'Foo', u'YZ']
[False, u'Foo  Baa,\xa0YZ', u'Foo  Baa', u'YZ']
[True, u'Foo,YZ', u'Foo', u'YZ']
[False, u'Foo  Baa,YZ', u'Foo  Baa', u'YZ']
[True, u'Foo,YZ\n', u'Foo', u'YZ']
[False, u'Foo  Baa,YZ\n', u'Foo  Baa', u'YZ']
[False, u'Foo,,YZ', u'Foo,', u'YZ']
[False, u'Foo  Baa,,YZ', u'Foo  Baa,', u'YZ']
[False, u'FooYZ', None, None]
[False, u'Foo  BaaYZ', u'Foo', u'BaaYZ']
[True, u'   Foo \t,\xa0   YZ \n', u'Foo', u'YZ']
[False, u'   Foo  Baa \t,\xa0   YZ \n', u'Foo  Baa', u'YZ']

+++ bothwell: 10 OK +++

=== paulger_v2 ===
[True, u'Foo YZ', u'Foo', u'YZ']
[False, u'Foo  Baa YZ', u'Foo  Baa', u'YZ']
[False, u'Foo YZ\n', u'Foo', u'Z\n']
[False, u'Foo  Baa YZ\n', u'Foo  Baa', u'Z\n']
[True, u'Foo\xa0YZ', u'Foo', u'YZ']
[False, u'Foo  Baa\xa0YZ', u'Foo  Baa', u'YZ']
[True, u'Foo  YZ', u'Foo', u'YZ']
[False, u'Foo  Baa  YZ', u'Foo  Baa', u'YZ']
[True, u'Foo, YZ', u'Foo', u'YZ']
[False, u'Foo  Baa, YZ', u'Foo  Baa', u'YZ']
[False, u'Foo, YZ\n', u'Foo', u'Z\n']
[False, u'Foo  Baa, YZ\n', u'Foo  Baa', u'Z\n']
[True, u'Foo,\xa0YZ', u'Foo', u'YZ']
[False, u'Foo  Baa,\xa0YZ', u'Foo  Baa', u'YZ']
[True, u'Foo,YZ', u'Foo', u'YZ']
[False, u'Foo  Baa,YZ', u'Foo  Baa', u'YZ']
[False, u'Foo,YZ\n', u'Foo', u'Z\n']
[False, u'Foo  Baa,YZ\n', u'Foo  Baa', u'Z\n']
[True, u'Foo,,YZ', u'Foo', u'YZ']
[False, u'Foo  Baa,,YZ', u'Foo  Baa', u'YZ']
[False, u'FooYZ', u'Fo', u'YZ']
[False, u'Foo  BaaYZ', u'Foo  Ba', u'YZ']
[False, u'   Foo \t,\xa0   YZ \n', u'Foo \t,\xa0   Y', u' \n']
[False, u'   Foo  Baa \t,\xa0   YZ \n', u'Foo  Baa \t,\xa0   Y', u' \n']

+++ paulger_v2: 7 OK +++

=== machin ===
[True, u'Foo YZ', u'Foo', u'YZ']
[True, u'Foo  Baa YZ', u'Foo Baa', u'YZ']
[True, u'Foo YZ\n', u'Foo', u'YZ']
[True, u'Foo  Baa YZ\n', u'Foo Baa', u'YZ']
[True, u'Foo\xa0YZ', u'Foo', u'YZ']
[True, u'Foo  Baa\xa0YZ', u'Foo Baa', u'YZ']
[True, u'Foo  YZ', u'Foo', u'YZ']
[True, u'Foo  Baa  YZ', u'Foo Baa', u'YZ']
[True, u'Foo, YZ', u'Foo', u'YZ']
[True, u'Foo  Baa, YZ', u'Foo Baa', u'YZ']
[True, u'Foo, YZ\n', u'Foo', u'YZ']
[True, u'Foo  Baa, YZ\n', u'Foo Baa', u'YZ']
[True, u'Foo,\xa0YZ', u'Foo', u'YZ']
[True, u'Foo  Baa,\xa0YZ', u'Foo Baa', u'YZ']
[True, u'Foo,YZ', u'Foo', u'YZ']
[True, u'Foo  Baa,YZ', u'Foo Baa', u'YZ']
[True, u'Foo,YZ\n', u'Foo', u'YZ']
[True, u'Foo  Baa,YZ\n', u'Foo Baa', u'YZ']
[True, u'Foo,,YZ', u'Foo', u'YZ']
[True, u'Foo  Baa,,YZ', u'Foo Baa', u'YZ']
[True, u'FooYZ', u'Foo', u'YZ']
[True, u'Foo  BaaYZ', u'Foo Baa', u'YZ']
[True, u'   Foo \t,\xa0   YZ \n', u'Foo', u'YZ']
[True, u'   Foo  Baa \t,\xa0   YZ \n', u'Foo Baa', u'YZ']

+++ machin: 24 OK +++

Upvotes: 1

Stephen Paulger
Stephen Paulger

Reputation: 5343

In your given examples state is always the last two characters citystate[-2:] and city is always everything up to that minus the trailing space and commas.

I'll add an extra example "New York, NY".

citystates = ["Greenwich, CT", "Greenwich,CT", "Greenwich CT", "New York, NY"]

for citystate in citystates:
    city, state = citystate[:-3].strip(", "), citystate[-2:]
    print "City '%s' is in '%s' % (city, state)

When run gives:

City 'Greenwich' is in 'CT'
City 'Greenwich' is in 'CT'
City 'Greenwich' is in 'CT'
City 'New York' is in 'NY'

Upvotes: 0

Hugh Bothwell
Hugh Bothwell

Reputation: 56634

def cityState(s):
    # split on last comma
    res = s.rsplit(',', 1)
    if len(res)==2:
        return res[0].strip(), res[1].strip()
    # otherwise split on last non-trailing whitespace
    res = s.rsplit(None, 1)
    if len(res)==2:
        return res[0].lstrip(), res[1]
    # otherwise split failed
    raise ValueError("Could not split {0} into city, state".format(s))

for city_state in ["Greenwich, CT", "Greenwich,CT", "Greenwich CT", "New York, NY"]:
    print "City '{0}' is in '{1}'".format(*cityState(city_state))

results in

City 'Greenwich' is in 'CT'
City 'Greenwich' is in 'CT'
City 'Greenwich' is in 'CT'
City 'New York' is in 'NY'

Upvotes: 0

Rafe Kettler
Rafe Kettler

Reputation: 76955

import re
city, state = re.split(r' ?,? ?', location)

To solve the New York, NY problem, use slicing:

split_loc = re.split(r' ?,? ?', location)
city = ' '.join(split_loc[:-1]) # Everything up to last element joined by space
state = split_loc[-1]

Upvotes: 4

Related Questions