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

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

鉴于数组%w(Aarhus Aalborg Assens)我想让['Assens', 'Aalborg', 'Aarhus']回归丹麦语中的正确顺序。

标准排序方法

 %w(Aarhus Aalborg Assens).sort 

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

 ["Aalborg", "Aarhus", "Assens"] 

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

根据维基百科 :

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

这会甩掉排序。

这样做是为了解决问题:

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

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

这样做的原因是sort_by做了Schwartzian变换 ,所以它实际上是按块返回的返回值进行排序,在这种情况下,是’Aa’替换为’Å’的名称。 替换是临时的,并在排序数组时被丢弃。

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

编辑:

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

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

我在Github上找到了ffi-locale ,就我所见,这解决了我的问题。

它允许以下代码:

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

返回正确的结果:

 => ["Assens", "Aalborg", "Aarhus"] 

我还没有调查性能,但它调用了本机代码,因此Ruby字符替换代码应该更快…

更新
它并不完美:(它在Snow Leopard上无法正常运行 – 似乎strcollfunction在OS X上被破坏并且已经有一段时间了。这对我来说很烦人但是部署的主要平台是linux – 它的工作原理 – 所以这是我目前首选的解决方案。