是否有内置的字符串自然排序函数?

420 投票
24 回答
156154 浏览
提问于 2025-04-16 10:50

我有一串字符串,想要对它们进行一种叫做自然字母排序的排序方式。

比如说,下面这个列表就是我想要的自然排序结果:

['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']

而这是我用sorted()函数得到的“排序”版本:

['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']

我在寻找一个排序函数,它的表现方式跟第一个一样。

24 个回答

145

这是一个更符合Python风格的版本,来自Mark Byer的回答:

import re

def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
    return [int(text) if text.isdigit() else text.lower()
            for text in _nsre.split(s)]

现在这个函数可以作为关键字在任何使用它的函数中使用,比如 list.sortsortedmax 等等。

作为一个lambda表达式:

lambda s: [int(t) if t.isdigit() else t.lower() for t in re.split('(\d+)', s)]

完整可复现的示例代码:

import re
natsort = lambda s: [int(t) if t.isdigit() else t.lower() for t in re.split('(\d+)', s)]
L = ["a1", "a10", "a11", "a2", "a22", "a3"]   
print(sorted(L, key=natsort))  
# ['a1', 'a2', 'a3', 'a10', 'a11', 'a22'] 
263

试试这个:

import re

def natural_sort(l): 
    convert = lambda text: int(text) if text.isdigit() else text.lower()
    alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
    return sorted(l, key=alphanum_key)

输出结果:

['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']

这段代码是从这里改编过来的:为人类排序:自然排序顺序

373

在PyPI上有一个第三方库叫做 natsort(顺便说一下,我是这个库的作者)。对于你的情况,你可以选择以下任意一种方法:

>>> from natsort import natsorted, ns
>>> x = ['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']
>>> natsorted(x, key=lambda y: y.lower())
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
>>> natsorted(x, alg=ns.IGNORECASE)  # or alg=ns.IC
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']

你需要注意的是,natsort使用了一种通用的算法,所以它应该能处理你输入的几乎所有内容。如果你想了解更多关于为什么选择这个库而不是自己写一个函数的信息,可以查看natsort文档中的工作原理页面,特别是特殊情况随处可见!这一部分。


如果你需要一个排序关键字而不是排序函数,可以使用下面的任意公式。

>>> from natsort import natsort_keygen, ns
>>> l1 = ['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
>>> l2 = l1[:]
>>> natsort_key1 = natsort_keygen(key=lambda y: y.lower())
>>> l1.sort(key=natsort_key1)
>>> l1
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
>>> natsort_key2 = natsort_keygen(alg=ns.IGNORECASE)
>>> l2.sort(key=natsort_key2)
>>> l2
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']

更新于2020年11月

因为一个常见的请求/问题是“如何像Windows资源管理器那样排序?”(或者你操作系统的文件浏览器),从natsort版本7.1.0开始,有一个叫做os_sorted的函数可以做到这一点。在Windows上,它会按照Windows资源管理器的顺序进行排序,而在其他操作系统上,它应该会像本地文件系统浏览器那样排序。

>>> from natsort import os_sorted
>>> os_sorted(list_of_paths)
# your paths sorted like your file system browser

对于需要排序关键字的用户,可以使用os_sort_keygen(或者如果你只需要默认值,可以使用os_sort_key)。

注意 - 在使用这个函数之前,请阅读API文档,以了解其限制和如何获得最佳结果。

撰写回答