错误的匈牙利语 (hu_HU) 排序顺序

问题描述 投票:0回答:1
import locale
locale.setlocale(locale.LC_COLLATE,'hu_HU.ISO8859-2')
print(sorted(['c', 'á', 'b', 'z', 'é', 'a', 'd', 'e', 'f', 'Ő', 'Ű', 'ő', 'ű'], key=locale.strxfrm))

预期:['a', 'á', 'b', 'c', 'd', 'e', 'é', 'f', 'Ő', 'ő', 'Ű', 'ű ', 'z']

实际:['a', 'á', 'b', 'c', 'd', 'e', 'é', 'f', 'z', 'Ő', 'ő', 'Ű ', 'ű']

请注意,“z”应该是最后一个字母。

我知道我的代码“有效”,因为它确实将“á”和“é”放在正确的位置(并且“常规”排序将它们放在“z”之后),因此我的错误位于语言环境定义中。

我有MacOS Venture 13.6.4,python 3.11.7

如何“更新”区域设置定义?是Python中的东西还是使用系统区域设置?

注意:我尝试安装PyICU和zope.ucol,但在安装过程中都失败了,所以不要告诉我使用它们。

python locale strxfrm
1个回答
0
投票

语言敏感排序在 Python 中是一个复杂的问题:

共有三种方法:

  1. 使用PyICU
  2. 使用基于区域设置的排序键
  3. 创建您自己的函数来处理排序键
  1. 如果您的 Python 代码需要在多个操作系统上运行,PyICU 是最好的跨平台解决方案。
import icu
collator = icu.Collator.createInstance(icu.Locale('hu_HU'))
data = ['c', 'á', 'b', 'z', 'é', 'a', 'd', 'e', 'f', 'Ő', 'Ű', 'ő', 'ű']
print(sorted(data, key=collator.getSortKey))
# ['a', 'á', 'b', 'c', 'd', 'e', 'é', 'f', 'ő', 'Ő', 'ű', 'Ű', 'z']

但是OP更愿意避开这个解决方案。

  1. 结果会因平台和 libc 实现而异。

基本代码是:

import locale
locale.setlocale(locale.LC_COLLATE,'hu_HU.UTF-8')
data = ['c', 'á', 'b', 'z', 'é', 'a', 'd', 'e', 'f', 'Ő', 'Ű', 'ő', 'ű']
print(sorted(data, key=locale.strxfrm))

结果各不相同。 macOS 不支持匈牙利语排序规则。不使用 glibc 的 Linux 发行版将不支持匈牙利排序规则。我没有将 Windows 包含在下表中,但它可以正常工作。

Alpine: ['a', 'b', 'c', 'd', 'e', 'f', 'z', 'á', 'é', 'Ő', 'ő', 'Ű', 'ű']
Freebsd: ['a', 'á', 'b', 'c', 'd', 'e', 'é', 'f', 'ő', 'Ő', 'ű', 'Ű', 'z']
macOS: 'a', 'b', 'c', 'd', 'e', 'f', 'z', 'á', 'é', 'Ő', 'ő', 'Ű', 'ű']
Ubuntu: ['a', 'á', 'b', 'c', 'd', 'e', 'é', 'f', 'ő', 'Ő', 'ű', 'Ű', 'z']
  1. 另一种方法是编写一个自定义函数来使用重音和不区分大小写的排序键:
import unicodedata as ud
import regex
data = ['c', 'á', 'b', 'z', 'é', 'a', 'd', 'e', 'f', 'Ő', 'Ű', 'ő', 'ű']
# accent and case insensitive
def ai_si(x):
    xn = ud.normalize("NFD", x.casefold())
    xn = regex.sub(r'\p{Mn}', '', xn)
    return (xn, x.swapcase())
print(sorted(data, key=ai_si))

ai_si()
返回一个元组
(xn, x.swapcase())
。如果仅返回
xn
,大小写和变音符号将被完全忽略,这意味着它们在最终排序中的位置是相对于它们在列表中的位置的。 IE。
á
Á
a
A
相对于彼此没有任何固定顺序,它将由要排序的原始列表中的位置确定。

我们可以使用

x
x.swapcase()
作为元组的第二个元素。
x
将创建一个排序顺序,其中大写字符通常(但并非总是)排在小写字符之前。而
x.swapcase()
则颠倒了事例之间的相对顺序。还有其他方法可以构造元组的第二个元素。

ai_si()
允许对变音符号和大小写进行二次区分。

© www.soinside.com 2019 - 2024. All rights reserved.