如何使用Python获得“合理”的字符串排序?

如何使用Python获得“合理”的字符串排序?,python,sorting,natsort,Python,Sorting,Natsort,我的用户大多是德国人,他们需要从一个长列表中选择元素。我将实现自动完成,但我也希望按照他们期望的顺序向他们展示元素。我向几个用户询问了典型字符串的排序,发现它们基本上是一致的。但是,很难实现这种排序: user_expectation(l) " < @ 1 2 10 10abc A e é E

我的用户大多是德国人,他们需要从一个长列表中选择元素。我将实现自动完成,但我也希望按照他们期望的顺序向他们展示元素。我向几个用户询问了典型字符串的排序,发现它们基本上是一致的。但是,很难实现这种排序:

user_expectation(l)                               "        <        @        1        2        10       10abc    A        e        é        E        Z
sorted(l)                                         "        1        10       10abc    2        <        @        A        E        Z        e        é
sorted(l, key=lambda w: w.lower())                "        1        10       10abc    2        <        @        A        e        E        Z        é
ns.natsorted(l)                                   1        2        10       10abc    "        <        @        A        E        Z        e        é
ns.natsorted(l, alg=ns.I)                         1        2        10       10abc    "        <        @        A        E        Z        e        é
ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G)     1        2        10       10abc    "        <        @        A        E        e        Z        é
ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G), en 1        2        10       10abc    <        "        @        A        E        e        é        Z
ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G), de 1        2        10       10abc    <        "        @        A        E        e        é        Z
ns.natsorted(l, alg=ns.LF | ns.G), de             1        2        10       10abc    "        <        @        A        e        E        Z        é
因此:

首先是特殊字符-顺序并不重要,只要是一致的 接下来是数字。通过匹配前缀对数字进行数字排序,因此['1','10','2'] 拉丁字母1? 非重音优先 大写前小写,但这可能并不那么重要 口音/特别的 密码 natsort和IGNORECASE、LOWERCASEFIRST、LOCALE de或en组非常接近。我不喜欢的是特殊字符在数字后面。有办法解决吗?LF似乎没有效果

您可以使用键参数将特殊字符替换为在数字之前排序的字符,例如空格

sorted或natsorted随后将按修改后的字符串进行排序,但仍将返回原始字符串

一个简化的例子,只处理特殊字符和数字

进口稀土 def替换_特殊件: 根据需要向正则表达式添加更多字符 返回re.sub'[自natsort版本>=5.1.0起,重音字符应立即处理

下面是一种将特殊字符置于数字之前的方法

import re
import natsort as ns

def special_chars_first(x):
    '''Ensure special characters are sorted first.'''
    # You can add error handling here if needed.
    # If you need '_' to be considered a special character,
    # use [0-9A-Za-z] instead of \W.
    return re.sub(r'^(\W)', r'0\1', x)
    # An alternate, less-hacky solution.
    #if re.match(r'\W', x):
    #    return float('-inf'), x
    #else:
    #    return float('inf'), x

l = ['"', "<", "@", "1", "2", "10", "10abc", "A", "e", "é", "E", "Z"]
print(ns.natsorted(l, key=special_chars_first, alg=ns.G | ns.LF))
输出

['"', '<', '@', '1', '2', '10', '10abc', 'A', 'e', 'é', 'E', 'Z']

这是通过在任何以非单词字符开头的字符串前面加前缀来实现的,该字符定义为除字母、数字或带有“0”的“uu”之外的任何字符,这将保证它们在任何其他数字之前结束,并且根据now natsort works,数字始终是第一位的。

是否所有特殊字符都应该在数字之后,或者如果该字符串只是特殊字符字符?例如,@和@hello都应该在1之前吗?所有特殊字符都应该在数字之前。所以,@和@hello都应该在1之前。你能更新用户在问题中的预期顺序,以便复制/粘贴显示正确的结果吗?根据你对我的评论的回复,用户应该是1、2、10,而不是1、10、2、10在问题的两个示例中,它们仍然显示了后者而不是前者。@SethMMorton感谢您,规范化数据的功能应该内置于natsort中。我为此提出了一个问题:当列表项以00开头时,您的特殊字符第一个解决方案将中断。我不同意。我只是在给定列表中添加了00@并获得了输出['','奇怪…但是,好吧,只需将00添加到列表中即可。@poke如果添加几个前导零会把事情搞砸,这将不是一个非常健壮的自然排序算法:
['"', '<', '@', '1', '2', '10', '10abc', 'A', 'e', 'é', 'E', 'Z']