我有一个电子邮件地址列表,其格式如下:
### @ email.com
名但这个数字并不总是存在。例如:john45 @ email.com,bob @ email.com joe2@email.com等。我想用数字对这些名称进行排序,而没有数字的名字则先排序。我想出了一些有用的东西,但对Python来说是新手,我很好奇是否有更好的方法。这是我的解决方案:
import re
def sortKey(name):
m = re.search(r'(\d+)@', name)
return int(m.expand(r'\1')) if m is not None else 0
names = [ ... a list of emails ... ]
for name in sorted(names, key = sortKey):
print name
这是我脚本中唯一一次使用“sortKey”,所以我更喜欢它是一个lambda函数,但我不知道该怎么做。我知道这会奏效:
for name in sorted(names, key = lambda n: int(re.search(r'(\d+)@', n).expand(r'\1')) if re.search(r'(\d+)@', n) is not None else 0):
print name
但我认为我不应该两次调用re.search来做到这一点。在Python中最优雅的方法是什么?
答案 0 :(得分:5)
最好使用re.findall
,就像没有找到数字一样,然后返回一个空列表,该列表将在填充列表之前排序。用于排序的密钥是找到的任何数字(转换为整数),后跟字符串本身......
emails = 'john45@email.com bob@email.com joe2@email.com'.split()
import re
print sorted(emails, key=lambda L: (map(int, re.findall('(\d+)@', L)), L))
# ['bob@email.com', 'joe2@email.com', 'john45@email.com']
使用john1
而不是输出:['bob@email.com', 'john1@email.com', 'joe2@email.com']
表示虽然在joe之后按字典顺序排列,但是这个数字首先考虑了john
。
如果您希望保留现有的使用re.search的方法(但是很糟糕),那么有一种不太常见的方式:
getattr(re.search('(\d+)@', s), 'groups', lambda: ('0',))()