在 python 中将西里尔字符串排在拉丁语之前

问题描述 投票:0回答:5

在我的数据库中,我有西里尔字符和拉丁字符的记录。默认情况下,它们按字母顺序排列,拉丁语记录在前:

abc...bcd...cde...абв...

我想把西里尔字母放在首位:

абв...abc...bcd...cde...

到目前为止我尝试了什么:

  1. 这个解决方案。它不是很好,因为它只按 第一个词,我可以同时拥有西里尔文和拉丁文词 字符串(甚至是同一个单词中的混合字符)。

  2. 用西里尔字母和拉丁字母写我自己的列表。它有效但是 一点都不好。我无法考虑所有可能的字母 在两个字母表中,包括带有变音符号的字母表并写下它们 下来。

我也一直在研究 PyICU,但不知道如何使用它。

我猜我应该在这里使用一些自定义排序规则。问题是如何在实践中做到这一点。

python sorting unicode collation
5个回答
2
投票

一种方法是使用

transliterate
模块 或者
cytranslit
并使用排序键将所有内容音译为所需的字母表:

import transliterate

items = ['abc', 'bcd', 'cde', 'абв']

print(sorted(items, key=lambda x: transliterate.translit(x, 'ru')))

输出是期望的

['абв', 'abc', 'bcd', 'cde']

1
投票

IMO 这不是一件小事。我会说确实需要整理。

所以,假设一个键函数将字符串转换为代码点元组,其中所有非西里尔代码点将移动 100000):

import unicodedata

def key(s):
    SHIFT = 100000
    return tuple(
        ord(c) if is_cyrillic(c) else ord(c) + SHIFT
        for c in s
    )

def is_cyrillic(c):
    return unicodedata.name(c).startswith('CYRILLIC')        


>>> sorted(('wannt', 'waюnnt'), key=key)
Out[34]: ['waюnnt', 'wannt']

is_cyrillic
可以通过使用初步表或缓存数据库字符串中的西里尔字符来优化。


0
投票

如果是拉丁字符,您可以尝试通过在每个字符前面加上 1 来生成密钥,否则在前面加上 0:

sorted(items, key = lambda item : ['1' + x if x < '\x7f' else '0' + x for x in item])

0
投票

根据第一个字符排序的非常脏但可行的解决方案。它还消除了字母注册的差异。

ls = ['32', '24', 'xyz', 'WYZ', 'abc', 'абв', 'КЛМ', 'эюя', 'еёж', 'ёжз', '', '_']

def sort_rule(st):
    st = st.lower()
    ch = st[0] if st else ''       
    if ch >= 'а' and ch <= 'я':
        st = '1' + st
    elif ch == 'ё':
        st = '1е' + st
    elif ch >= 'a' and ch <= 'z':
        st = '2' + st
    else:
        st = '3' + st
    return st

sorted(ls, key=sort_rule)

> ['абв', 'еёж', 'ёжз', 'КЛМ', 'эюя', 'abc', 'WYZ', 'xyz', '', '24', '32', '_']

为了比较,默认排序给出下一个结果:

sorted(ls)

> ['', '24', '32', 'WYZ', '_', 'abc', 'xyz', 'КЛМ', 'абв', 'еёж', 'эюя', 'ёжз']

0
投票

这是一个老问题,有四个答案,但我觉得下面的答案更合适。

如果您同时安装了 icu4c 和 PyICU,则有一个相当简单的解决方案。 ICU 使用 CLDR 整理算法,这是 Unicode 整理算法的剪裁。

由于您希望首先对所有西里尔字符进行语言不敏感排序,因此最简单的方法是定制 CLDR 根排序规则。 ICU 排序规则的所有裁剪都是根排序规则的裁剪,您提供所需的最少更改。

在这种情况下,您只需要一个重新排序指令:

from icu import RuleBasedCollator
items = ['cde', 'abc', 'bcd', 'абв']
rules = "[reorder Cyrl]"
collator = RuleBasedCollator(rules)
sorted(items, key=collator.getSortKey)
# ['абв', 'abc', 'bcd', 'cde']

但是上面的规则完全符合Russian collation rules所做的,根据根排序规则重新排序西里尔字母。

from icu import Locale, Collator
items = ['cde', 'abc', 'bcd', 'абв']
collator = Collator.createInstance(Locale("ru"))
print(sorted(items, key=collator.getSortKey))
© www.soinside.com 2019 - 2024. All rights reserved.