使用Ruby/Rails中的特定排序规则对值进行排序

Hak*_*onB 12 ruby ruby-on-rails collation internationalization ruby-on-rails-3

是否可以使用Ruby中的特定排序规则对值数组进行排序?我需要根据da_DK排序规则进行排序.

鉴于%w(Aarhus Aalborg Assens)我想['Assens', 'Aalborg', 'Aarhus']回到的阵列,这是丹麦语的正确顺序.

标准排序方法

%w(Aarhus Aalborg Assens).sort
Run Code Online (Sandbox Code Playgroud)

返回看起来像ascii顺序的东西(至少不是丹麦语顺序):

["Aalborg", "Aarhus", "Assens"]
Run Code Online (Sandbox Code Playgroud)

环境是Snow Leopard和Linux运行ruby 1.9.2和Rails 3.0.5.

the*_*Man 6

根据维基百科:

在丹麦语和挪威语字母表中,与瑞典语相同的额外元音(见下文)也存在,但顺序不同,字形不同(......,X,Y,Z,Æ,Ø,Å).此外,"Aa"整理为"Å"的等价物.丹麦字母传统上将"W"视为"V"的变体,但今天"W"被视为一个单独的字母."

这会甩掉排序.

这样做是为了解决问题:

names = %w(Aarhus Aalborg Assens)
names.sort_by { |w| w.gsub('Aa', 'Å') } # => ["Assens", "Aalborg", "Aarhus"]
Run Code Online (Sandbox Code Playgroud)

和其他具有复合字符组合转换为单个字符的字母类似的东西.

这部作品的原因sort_by做了的Schwartzian变换,所以它实际上是由来自块,其中,在这种情况下,与"AA"替换为"A"的名义返回的返回值排序.替换是临时的,并在排序数组时被丢弃.

sort_by是非常强大的,但确实有一些开销.对于一个简单的排序,你应该使用,sort因为它更快.对于您在对象的顶层比较两个简单值的排序,无论您是否应该使用sort或,它都会变为清洗sort_by.如果你必须做更复杂的计算或在一个对象中挖掘,那么sort_by可以证明更快.没有一种真正的硬性方法可以知道哪个更好,所以我强烈建议使用基准测试,如果你必须对大型数组进行排序或处理对象,因为差异可能很大,有时sort可能会更好选择.

编辑:

Ruby本身并不会做你想要的,因为它不知道每个字符集的排序顺序.关于合并IBM的ICU讨论解释了为什么会这样.如果你想要ICU的能力,你可以看看ICU4R.我没有玩过它,但它听起来像是Ruby中唯一真正的解决方案.

您可以使用Postgres等数据库执行某些操作.它们支持各种整理选项,但通常会强制您在创建数据库时声明排序规则...或者可能是在创建表时...它已经有一段时间了,因为我创建了一个新表.无论如何,这是一个选择,虽然这将是一个痛苦.


Hak*_*onB 4

我在 Github 上找到了ffi-locale,据我所知,它解决了我的问题。

它允许使用以下代码:

FFILocale::setlocale FFILocale::LC_COLLATE, 'da_DK.UTF-8'
%w(Aarhus Aalborg Assens).sort { |a,b| FFILocale::strcoll(a, b) }
Run Code Online (Sandbox Code Playgroud)

返回正确的结果:

=> ["Assens", "Aalborg", "Aarhus"]
Run Code Online (Sandbox Code Playgroud)

我还没有研究性能,但它调用了本机代码,所以它应该比 Ruby 字符替换代码更快......

更新
它并不完美:( 它在 Snow Leopard 上无法正常工作 - 似乎 OS X 上的 strcoll 功能已损坏并且已经有一段时间了。这对我来说很烦人,但主要的部署平台是 linux - 它在那里有效 - 所以这是我目前的首选解决方案。