比较两个包含数字的Python字符串
更新:我应该早点说明这一点,但并不是所有的名称都是简单的数字。例如,有些名称前面加了“YT”的前缀。所以像“YT1.1”这样的名称,实际上你会遇到同样的问题,比如YT1.9应该小于YT1.11。我真的很惊讶字符串比较会失败……
你好,
这个问题应该很简单,但我找不到答案。我想按名称对一堆Excel工作表进行排序。每个名称都是数字,但它们的编号方式就像教科书中的“章节”一样,意思是章节4.11在4.10之后,而4.10又在4.9和4.1之后。我以为简单地将这些数字作为字符串进行比较就可以了,但我得到了以下结果:
>>> s1 = '4.11'
>>> s2 = '4.2'
>>> s1> s2
False
>>> n1 = 4.11
>>> n2 = 4.2
>>> n1 > n2
False
我该如何比较这两个值,使得4.11大于4.2呢?
5 个回答
1
你想要的东西叫做“自然排序”。这和“字典排序”是两回事。网上有很多方法可以实现这个功能,因为你想要的具体结果可能会因实现方式不同而有所不同。快速搜索一下就能找到一些例子(注意*这不是我的代码,我也没有测试过):
import re
def tryint(s):
try:
return int(s)
except:
return s
def alphanum_key(s):
""" Turn a string into a list of string and number chunks.
"z23a" -> ["z", 23, "a"]
"""
return [ tryint(c) for c in re.split('([0-9]+)', s) ]
def sort_nicely(l):
""" Sort the given list in the way that humans expect.
"""
l.sort(key=alphanum_key)
1
这不是一个内置的方法,但应该可以用:
>>> def lt(num1, num2):
... for a, b in zip(num1.split('.'), num2.split('.')):
... if int(a) < int(b):
... return True
... if int(a) > int(b):
... return False
... return False
...
... lt('4.2', '4.11')
0: True
这个代码可以再整理一下,但大致意思就是这样。
14
将名字转换成整数的元组,然后比较这些元组:
def splittedname(s):
return tuple(int(x) for x in s.split('.'))
splittedname(s1) > splittedname(s2)
更新: 由于你的名字可能包含数字以外的其他字符,所以你需要检查 ValueError
,并且对于那些无法转换为整数的值,保持它们不变:
import re
def tryint(x):
try:
return int(x)
except ValueError:
return x
def splittedname(s):
return tuple(tryint(x) for x in re.split('([0-9]+)', s))
要对名字列表进行排序,可以将 splittedname
作为 sorted
的关键函数:
>>> names = ['YT4.11', '4.3', 'YT4.2', '4.10', 'PT2.19', 'PT2.9']
>>> sorted(names, key=splittedname)
['4.3', '4.10', 'PT2.9', 'PT2.19', 'YT4.2', 'YT4.11']