如何构建一个 Python 比较器来按照 PostgreSQL 的方式对字符串进行排序?

How to build a Python comparator that sorts strings the way PostgreSQL does?

这个问题与this question基本相同,除了Python。

我希望查询 PostgreSQL 数据库中按电子邮件地址列排序的行,然后在 Python 中执行依赖于该排序的操作。

我正在查询的数据库正在使用 en_US.UTF8 排序规则,通过一些测试,我发现它对于电子邮件中的 @ 符号有一些特殊的行为地址:

mydb=> SELECT '0'  < '@';
 ?column? 
----------
 f
(1 row)

mydb=> SELECT '0'  < '@0';
 ?column? 
----------
 t
(1 row)

This answer 表明某些排序规则可能会忽略 @ 符号,但如果是这种情况,我会期望第二个查询出现 t

尽管 Python 提供了一个 locale module, that module has inconsistent behavior on some platforms,所以我似乎无法为此目的使用该模块。

根据该报告,我尝试了使用 PyICU package 的建议,这似乎很有希望:

>>> import icu
>>> collator = icu.Collator.createInstance()
>>> collator.getLocale()
<Locale: en_US>
>>> collator.getSortKey('0') < collator.getSortKey('@')
False
>>> collator.getSortKey('0') < collator.getSortKey('@0')
False

但如您所见,在上次比较中,它产生的顺序与 postgres 不同。

我试过为查询指定不同的排序规则,例如:

SELECT email COLLATE posix FROM mytable ORDER by email;

但这会导致错误:collation "posix" for encoding "UTF8" does not exist。我也尝试了 "en-us-x-icu" 的排序规则,但也不存在。

是否有任何方法可以按照 Python 程序可以依赖的顺序从 PostgreSQL 中可靠地查询一列电子邮件地址,方法是调整查询的排序规则或采用默认排序规则在 Python?

在 Postgres 中使用 collate "C"

with test(test) as (
values ('@'), ('@0'), ('0')
)

select test
from test
order by test collate "C"

 test 
------
 0
 @
 @0
(3 rows)

Python:

>>> test = ['@', '@0', '0']
>>> test.sort()
>>> test
['0', '@', '@0']