14

I have a list of full names which I am splitting into two variables currently like so:

first, last = full_name.split(" ")

which works only if full_name is two words when split, otherwise I get. Is there a concise way to account for a name with more parts to keep first as the first word and last as the rest of the words? I could do it with an extra line or two but I was wondering if there was an elegant way.

Frank Matranga
  • 183
  • 1
  • 2
  • 12
  • 1
    Can you provide some sample input and output? – Sohaib Farooqi Mar 13 '18 at 03:22
  • Can the first name not also be multi-word? In real life, I know people who go by first names like "Ellie Mae". (Not anyone with that *specific* first name, because I'm not from 1950s Oklahoma, but you know what I mean.) – abarnert Mar 13 '18 at 03:35

5 Answers5

12

Since you're using Python3, you can also use Extended Iterable Unpacking.

For example:

name = "John Jacob Jingleheimer Schmidt"
first, *last = name.split()
print("First = {first}".format(first=first))
#First = John
print("Last = {last}".format(last=" ".join(last)))
#Last = Jacob Jingleheimer Schmidt

This stores everything after the first element of the split string in last. Use " ".join(last) to put the string back together.

It also works if there's only two elements to unpack.

name = "John Schmidt"
first, *last = name.split()
print("First = {first}".format(first=first))
#First = John
print("Last = {last}".format(last=" ".join(last)))
#Last = Schmidt

Or if you wanted first, middle, and last:

name = "John Jacob Jingleheimer Schmidt"
first, middle, *last = name.split()
print("First = {first}".format(first=first))
#First = John
print("Middle = {middle}".format(middle=middle))
#Middle = Jacob
print("Last = {last}".format(last=" ".join(last)))
#Last = Jingleheimer Schmidt
pault
  • 41,343
  • 15
  • 107
  • 149
  • It even works if there's only one element to unpack. Try it with `"Cher"` and you'll get `Last = `, just as you'd presumably hope. That being said, I'm not sure it's worth redundantly splitting the last name just to join it back together. – abarnert Mar 13 '18 at 03:37
  • Also, since you're advertising new-ish features of Python here, why not use f-strings instead of explicit `format`? – abarnert Mar 13 '18 at 03:38
  • @abarnert Thanks for the comments. I'm not typically a python3 user, so I'm not totally familiar with all of the new features including f-strings. Feel free to edit the answer if you think it's worth including. (TBH, I only started using `.format` in my code this week- I come from a C++ background, so I'm comfortable with the C-style string formatting.) – pault Mar 13 '18 at 03:40
  • This is definitely the cleanest answer. – tbjers Feb 14 '21 at 07:28
9

Look into the second parameter of split

first, last = "First Last Second Last".split(" ", 1)

If full_name can be one word:

name_arr = full_name.split(" ", 1)
first = name_arr[0]
last = name_arr[1] if len(name_arr) > 1 else ""
eqwert
  • 507
  • 6
  • 15
  • This wont work if `full_name` consist of single word. – Sohaib Farooqi Mar 13 '18 at 03:20
  • I added a possible solution to fix that @bro-grammer . Thanks for the heads up! – eqwert Mar 13 '18 at 03:31
  • 2
    You can also use [str.partition](https://docs.python.org/3/library/stdtypes.html#str.partition) to avoid the conditional statement. – Sohaib Farooqi Mar 13 '18 at 03:32
  • 1
    @bro-grammer I think that's sufficiently different (and useful, because so many Python devs seem to not know about `partition` for some reason…) that you should write a separate answer. – abarnert Mar 13 '18 at 03:34
  • Oh wow, thanks @bro-grammer. Learned something new today! `str.partition` would suit this problem significantly better. – eqwert Mar 13 '18 at 03:37
7

You can use str.partition that guarantee three tuple output in the format:

(part before separator, separator itself, part after separator)

>>> "a".partition(" ")
>>> ('a', '', '')

>>> "a b".partition(" ")
>>> ('a', ' ', 'b')

>>> "a b c".partition(" ")
>>> ('a', ' ', 'b c')
Sohaib Farooqi
  • 5,457
  • 4
  • 31
  • 43
  • Nice, but it would be ideal to show it with `"a b c"` to demonstrate that it automatically solves the problem the OP was asking about. – abarnert Mar 13 '18 at 03:39
4

You can use:

first, last = full_name.split(" ", 1)
kiyah
  • 1,502
  • 2
  • 18
  • 27
4

I'd look into using the nameparser library. It makes extracting human names a walk in the park...

from nameparser import HumanName

# Here's a full name, with a nickname
full_name = 'Mr. Lin-Manuel "The Boss" Miranda'

# Extract values
parsed_name = HumanName(full_name)

# Get just the first and last name
f_name = parsed_name.first
l_name = parsed_name.last

print(f_name, l_name)
# Lin-Manuel Miranda

# ------------------------------

# If you want to see everything:
parsed_name.as_dict()
{'title': 'Mr.',
 'first': 'Lin-Manuel',
 'middle': '',
 'last': 'Miranda',
 'suffix': '',
 'nickname': 'The Boss'}
Yaakov Bressler
  • 9,056
  • 2
  • 45
  • 69