PHP中的自然排序算法,支持Unicode?

Ali*_*xel 20 php arrays sorting unicode utf-8

是否可以使用自然顺序算法在PHP中使用Unicode/UTF-8字符对数组进行排序?例如(此数组中的顺序正确排序):

$array = array
(
    0 => 'Agile',
    1 => 'Ágile',
    2 => 'Àgile',
    3 => 'Âgile',
    4 => 'Ägile',
    5 => 'Ãgile',
    6 => 'Test',
);
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用asort($ array),我会得到以下结果:

Array
(
    [0] => Agile
    [6] => Test
    [2] => Àgile
    [1] => Ágile
    [3] => Âgile
    [5] => Ãgile
    [4] => Ägile
)
Run Code Online (Sandbox Code Playgroud)

并使用natsort($ array):

Array
(
    [2] => Àgile
    [1] => Ágile
    [3] => Âgile
    [5] => Ãgile
    [4] => Ägile
    [0] => Agile
    [6] => Test
)
Run Code Online (Sandbox Code Playgroud)

如何在PHP 5下实现返回正确结果顺序(0,1,2,3,4,5,6)的函数?我的系统上可以使用所有多字节字符串函数(mbstring,iconv,...).

编辑:我想natsort()值,而不是键 - 我明确定义键(和使用asort()而不是sort())的唯一原因是为了简化找出排序的位置的工作unicode值出错了.

Ste*_*rig 25

问题并不像第一眼看上去那么容易回答.这是PHP缺乏unicode支持的领域之一.

natsort()其他海报建议的所有内容与排序您想要排序的类型的数组无关.您正在寻找的是区域设置感知排序机制,因为使用扩展字符排序字符串始终是使用语言的问题.让我们以德语为例:A和Ä有时可以按照相同的字母(DIN 5007/1)进行分类,有时Ä可以按照事实上的"AE"(DIN 5007/2)进行分类.相比之下,在瑞典语中,Ä出现在字母表的末尾.

如果您不使用Windows,那么您很幸运,因为PHP提供了一些功能.使用的组合setlocale(),usort(),strcoll()和正确的UTF-8区域设置你的语言,你得到的东西是这样的:

$array = array('Àgile', 'Ágile', 'Âgile', 'Ãgile', 'Ägile', 'Agile', 'Test');
$oldLocal = setlocale(LC_COLLATE, '<<your_RFC1766_language_code>>.utf8');
usort($array, 'strcoll');
setlocale(LC_COLLATE, $oldLocal);
Run Code Online (Sandbox Code Playgroud)

请注意,为了对UTF-8字符串进行排序,必须使用UTF-8语言环境变体.我将上面示例中的区域设置重置为其原始值,因为设置区域设置setlocale()可以在其他正在运行的PHP脚本中引入副作用 - 有关详细信息,请参阅PHP手册.

当您使用Windows机器时,目前没有解决此问题的方法,并且在我假设的PHP 6之前不会有任何解决方案.请参阅我自己的问题上SO针对这一特定问题.


Ali*_*xel 12

搞定了!

$array = array('Ägile', 'Ãgile', 'Test', '????', '????', 'Ágile', 'Àgile', 'Âgile', 'Agile');

function Sortify($string)
{
    return preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|tilde|uml);~i', '$1' . chr(255) . '$2', htmlentities($string, ENT_QUOTES, 'UTF-8'));
}

array_multisort(array_map('Sortify', $array), $array);
Run Code Online (Sandbox Code Playgroud)

输出:

Array
(
    [0] => Agile
    [1] => Ágile
    [2] => Âgile
    [3] => Àgile
    [4] => Ãgile
    [5] => Ägile
    [6] => Test
    [7] => ????
    [8] => ????
)
Run Code Online (Sandbox Code Playgroud)

更好的是:

if (extension_loaded('intl') === true)
{
    collator_asort(collator_create('root'), $array);
}
Run Code Online (Sandbox Code Playgroud)

感谢@tchrist!

  • 听起来你真正需要的是Unicode校对算法(UCA).我有一个Perl演示[在这个答案](http://stackoverflow.com/questions/1097908/how-do-i-sort-unicode-strings-alphabetically-in-python/5024116#5024116),我在那里为那些可能没有适当的库来调用的人提供可以shell调用的版本.也许这也可能对此有所帮助. (3认同)