这几天在搞一个网站,里面涉及到对一些数据进行排序显示的问题。后来做完之后自己用着发现因为默认是按英文排序的,当语言是中文的时候要找一个项特别麻烦。那么问题就来了,中文要怎么样才能按照用户习惯的顺序来排序呢(中国大陆来说,就是拼音排序)?
经过一番百度Google,找到的资料要么就是转成GB2312
然后排序,要么就是查表之类的,费劲又不安全(转码的时候可能会有意外字符导致失败之类的,而且GB2312
并不完全是按拼音排序的;查表的话数据的正确性难以有保障)。作为一个对代码正确性要求很高的人,这显然不符合我的风格。
然后我突然想到了万能的Unicode
。Unicode
并不只是单纯的一个编码系统,而是有关语言文字的很多内容的一整套完整的编码、属性体系。我这个项目里面用到的翻译部分就是使用了PHP的intl
扩展,而这个扩展是基于ICU
这个项目实现的,而ICU
又是基于Unicode组织提供的CLDR
数据开发的一套完整的国际化解决方案。CLDR
,全称叫做Unicode Common Locale Data Repository
,是Unicode组织提供的一套基本的语言相关的数据,包含了日期时间货币数字格式等等东西,也包含了排序规则,这就是本文要用到的东西。
废话讲完了,开始说正题。下面以三个国家名为例。
新西兰
贝宁
澳大利亚
选这三个国家的原因是,PHP默认排序(sort
)、拼音排序以及笔画排序应用到这三个国家上面的结果都不一样,方便查看效果。代码如下:
<?php
$data = ['新西兰', '贝宁', '澳大利亚'];
sort($data); // 默认排序(即直接按照二进制排序)
var_dump($data);
$coll = collator_create('zh-CN'); // 使用中国大陆的语言习惯(拼音排序)
usort($data, [$coll, 'compare']);
var_dump($data);
$coll = collator_create('zh-TW'); // 使用台湾的语言习惯(笔画排序)
usort($data, [$coll, 'compare']);
var_dump($data);
在上面代码中根据语言习惯排序的时候使用了Collator::compare
作为自定义比较函数,这样通过指定不同的语言,就能得到不同的排序结果。上面代码的结果如下:
array(3) {
[0]=>
string(9) "新西兰"
[1]=>
string(12) "澳大利亚"
[2]=>
string(6) "贝宁"
}
array(3) {
[0]=>
string(12) "澳大利亚"
[1]=>
string(6) "贝宁"
[2]=>
string(9) "新西兰"
}
array(3) {
[0]=>
string(6) "贝宁"
[1]=>
string(9) "新西兰"
[2]=>
string(12) "澳大利亚"
}
需要注意的是,这个Collator类里面还提供了一个sort
函数和一个sortWithSortKeys
函数,sort
函数的效果似乎和PHP语言提供的sort
效果完全一样,而sortWithSortKeys
的效果完全不知所云。。另外,以上代码需要安装PHP的intl
扩展才能正确运行,而且intl
扩展还依赖icu
库,所以最好先装最新的icu
库然后再装intl
扩展。
另外,可能也有需要在语言是简体中文(即Locale是zh-CN
)的时候按照笔画数排序,那么这时候可以在Locale
后面加参数,比如zh-CN-u-co-stroke
或者zh-CN@collation=stroke
的效果就是笔画排序,当然还有一些其他参数可选,可以参考这里。