我有需要从长列表中选择元素的用户(主要是德国人)。我将实现自动完成,但我也想按照他们期望的顺序向他们展示元素。我向几个用户询问了典型的字符串来对它们进行排序,发现它(大部分)是一致的。但是,很难实现这种排序:
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'])
- 字符(Latin1?)
- 先不重音
- 大写之前的小写(尽管这可能不是那么重要
- 稍后重音/特殊的
代码
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import natsort as ns
import locale
def custom_print(name, l):
s = u"{:<50}".format(name)
for el in l:
s += u"{:<5}\t".format(el)
print(u"\t" + s.strip())
l = ['"', "<", "@", "1", "2", "10", "10abc", "A", "e", "é", "E", "Z"]
custom_print("user_expectation(l)", l)
custom_print("sorted(l)", sorted(l))
custom_print("sorted(l, key=lambda w: w.lower())",
sorted(l, key=lambda w: w.lower()))
custom_print("ns.natsorted(l)", ns.natsorted(l))
custom_print("ns.natsorted(l, alg=ns.I)", ns.natsorted(l, alg=ns.I))
custom_print("ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G)",
ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G))
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
custom_print("ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G), en",
ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G))
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
custom_print("ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G), de",
ns.natsorted(l, alg=ns.LOCALE | ns.LF | ns.G))
custom_print("ns.natsorted(l, alg=ns.LF | ns.G), de",
ns.natsorted(l, alg=ns.LF | ns.G))
natsort
使用IGNORECASE
, LOWERCASEFIRST
, LOCALE
(de 或 en),GROUP
标志非常接近。我不喜欢的是特殊字符在数字之后。有没有办法解决它?(而且LF
似乎没有效果)