Join author names with first ones separated by com

2020-05-09 22:32发布

问题:

I'm completely new to Python and have a list of names separated by \and, which I need to join separating the first ones with comma and the last one by 'and'. However if there are more than 4 names the return value should be the first name along with the phrase 'et al.'. So if I have

 authors = 'John Bar \and Tom Foo \and Sam Foobar \and Ron Barfoo'

I should get 'John Bar et al.'. Whereas with

authors = 'John Bar \and Tom Foo \and Sam Foobar'

I should get 'John Bar, Tom Foo and Sam Foobar'.

It should also work with just one author name, returning that single name (and surname) by itself.

I tried doing something like

  names = authors.split('\and')
  result = ', '.join(names[:-1]) + ' and '.join(names[-1])

But that obviously doesn't work. So my question is how can I use join and split to get the first authors separated by comma and the last by 'and' taking into account that if there are more than four authors only the first author name should be returned along with 'et al.'.

回答1:

Start with splitting out the names:

names = [name.strip() for name in authors.split(r'\and')]  # assuming a raw \ here, not the escape code \a.

Then rejoin based on the length:

if len(names) >= 4:
    authors = '{} et al.'.format(names[0])
elif len(names) > 1:
    authors = '{} and {}'.format(', '.join(names[:-1]), names[-1])
else:
    authors = names[0]

This works for entries with just one author too; we just reassign the name to authors.

Combined into a function:

def reformat_authors(authors):
    names = [name.strip() for name in authors.split(r'\and')]
    if len(names) >= 4:
        return '{} et al.'.format(names[0])
    if len(names) > 1:
        return '{} and {}'.format(', '.join(names[:-1]), names[-1])
    return names[0]

with a demo:

>>> reformat_authors(r'John Bar \and Tom Foo \and Sam Foobar \and Ron Barfoo')
'John Bar et al.'
>>> reformat_authors(r'John Bar \and Tom Foo \and Sam Foobar')
'John Bar, Tom Foo and Sam Foobar'
>>> reformat_authors(r'John Bar \and Tom Foo')
'John Bar and Tom Foo'
>>> reformat_authors(r'John Bar')
'John Bar'


回答2:

Let's split this problems into parts:

First, get a list of the individual authors:

>>> authors = 'John Bar \\and Tom Foo \\and Sam Foobar \\and Ron Barfoo'
>>> authorlist = [item.strip() for item in authors.split("\\and")]
>>> authorlist
['John Bar', 'Tom Foo', 'Sam Foobar', 'Ron Barfoo']

Now check for the number of entries in the list and act accordingly:

>>> if len(authorlist) > 3:
...     print("{0} et al.".format(authorlist[0]))
... elif len(authorlist) == 1:
...     print(authorlist[0])
... else:
...     print("{0} and {1}".format(", ".join(authorlist[:-1]), authorlist[-1]))
...
John Bar et al.


回答3:

def natural_join(val, cnj="and"):
    if isinstance(val, list):
        return " ".join((", ".join(val[0:-1]), "%s %s" % (cnj, val[-1]))) if len(val) > 1 else val[0]
    else:
        return val

natural_join(['pierre'])
# 'pierre'

natural_join(['pierre', 'paul'])
# 'pierre and paul'

natural_join(['pierre', 'paul', 'jacques'])
# 'pierre, paul and jacques'

natural_join(['pierre', 'paul', 'jacques'], cnj="et")
# 'pierre, paul et jacques'


回答4:

Looks like you should check out the string.split method. You've got a few cases here: either there's one name, there are 2-3 names, or there are 4+ names. Each of these needs separate handling, so just figure out what needs to be done in each case:

# First split up the names by your specified delimiter (and strip off whitespace)
names = [name.strip() for name in authors.split(r'\and')]

# Now deal with your three cases for formatting.
if len(names) == 1:
    print names[0]
elif len(names) < 4:
    print ', '.join(names[:-1])+' and '+names[-1]
else:
    print names[0]+' et al.'


回答5:

First you should split your tring, to get the names using split.

parts = author.split(' \and ')

Then You apply your conditions:

  1. If there are 4 or more names, return the first name + ' el at'

    if len(parts) >= 4:
        return parts[0]+' et al'
    
  2. If there are more than 1 names, join them with a ', ' and the last one with a ' and '

    elif len(parts) > 1:
        return ' and '.join([', '.join(parts[:-1]), parts[-1]])
    
  3. If there is only one name, return that name.

    return parts[0] 
    

The final function:

def my_func(author):
    parts = author.split(' \and ')
    if len(parts) >= 4:
        return parts[0]+' et al'
    elif len(parts) > 1:
        return ' and '.join([', '.join(parts[:-1]), parts[-1]])
    return parts[0] 


标签: python join