我有用户(主要是德国人)需要从长列表中选择元素.我将实现自动完成,但我也想按照他们期望的顺序向他们展示元素.我问了几个用户对典型字符串进行排序,发现它(大多数)是一致的.但是,很难实现这种排序:
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 flags非常接近.我不喜欢的是特殊字符在数字之后.有办法解决吗? (而LF似乎没有效果)
解决方法:
从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”来保证它们在任何其他数字之前结束(并且数字总是首先根据到现在natsort工作).
标签:python,sorting,natsort
来源: https://codeday.me/bug/20190705/1390660.html