前言
在 PHP 中,國際化的功能非常豐富,包括很多我們可能都不知道的東西其實(shí)都非常有用,比如說今天要介紹的這一系列的字符排序和比較的功能。
排序
正常來說,如果我們對(duì)數(shù)組中的字符進(jìn)行排序,按照的是字符的 ASC2 表的順序進(jìn)行排列,如果是英文還好,但對(duì)于中文的話,排序出來的結(jié)果會(huì)是非常懵逼的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
$arr = [ '我' , '是' , '硬' , '核' , '項(xiàng)' , '目' , '經(jīng)' , '理' ]; sort( $arr ); var_dump( $arr ); // array(8) { // [0]=> // string(3) "我" // [1]=> // string(3) "是" // [2]=> // string(3) "核" // [3]=> // string(3) "理" // [4]=> // string(3) "目" // [5]=> // string(3) "硬" // [6]=> // string(3) "經(jīng)" // [7]=> // string(3) "項(xiàng)" // } |
按照我們的習(xí)慣會(huì)以中文的拼音來對(duì)漢字進(jìn)行排序,這個(gè)時(shí)候往往大家都會(huì)選擇自己寫排序的算法或者去找合適的 Composer 包。其實(shí),PHP 中已經(jīng)為我們準(zhǔn)備了一個(gè)對(duì)象就是用來處理這類問題的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$coll = new Collator( 'zh_CN' ); $coll ->sort( $arr ); var_dump( $arr ); // array(8) { // [0]=> // string(3) "核" // [1]=> // string(3) "經(jīng)" // [2]=> // string(3) "理" // [3]=> // string(3) "目" // [4]=> // string(3) "是" // [5]=> // string(3) "我" // [6]=> // string(3) "項(xiàng)" // [7]=> // string(3) "硬" // } |
沒錯(cuò),正是這個(gè) Collator 類。它在實(shí)例化的時(shí)候需要指定當(dāng)前的區(qū)域,比如我們指定為 zh_CN ,也就是中文字符區(qū)域,這時(shí)候再使用它的 sort() 方法就可以完成對(duì)中文字符的拼音排序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
$coll ->sort( $arr , Collator::SORT_NUMERIC ); var_dump( $arr ); // array(8) { // [0]=> // string(3) "核" // [1]=> // string(3) "經(jīng)" // [2]=> // string(3) "理" // [3]=> // string(3) "目" // [4]=> // string(3) "是" // [5]=> // string(3) "我" // [6]=> // string(3) "項(xiàng)" // [7]=> // string(3) "硬" // } $coll ->sort( $arr , Collator::SORT_STRING ); var_dump( $arr ); // array(8) { // [0]=> // string(3) "核" // [1]=> // string(3) "經(jīng)" // [2]=> // string(3) "理" // [3]=> // string(3) "目" // [4]=> // string(3) "是" // [5]=> // string(3) "我" // [6]=> // string(3) "項(xiàng)" // [7]=> // string(3) "硬" // } |
Collator 對(duì)象的 sort() 方法還支持第二個(gè)參數(shù),用于指定當(dāng)前的排序是按照字符還是數(shù)字格式進(jìn)行排序。對(duì)于純中文的內(nèi)容來說,這個(gè)沒有什么區(qū)別。
除了 sort() 方法之外,它還有一個(gè) asort() 方法,就和普通的 asort() 函數(shù)一樣的功能,只不過它也是支持不同的區(qū)域語言的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
$arr = [ 'a' => '100' , 'b' => '7' , 'c' => '50' ]; $coll ->asort( $arr , Collator::SORT_NUMERIC ); var_dump( $arr ); // array(3) { // ["b"]=> // string(1) "7" // ["c"]=> // string(2) "50" // ["a"]=> // string(3) "100" // } $coll ->asort( $arr , Collator::SORT_STRING ); var_dump( $arr ); // array(3) { // ["a"]=> // string(3) "100" // ["c"]=> // string(2) "50" // ["b"]=> // string(1) "7" // } $arr = [ '中' => '100' , '的' => '7' , '文' => '50' ]; $coll ->asort( $arr , Collator::SORT_NUMERIC ); var_dump( $arr ); // array ( // '的' => '7', // '文' => '50', // '中' => '100', // ) $coll ->asort( $arr , Collator::SORT_STRING ); var_dump( $arr ); // array ( // '中' => '100', // '文' => '50', // '的' => '7', // ) |
asrot() 方法是根據(jù)鍵和值一起進(jìn)行排序的,所以在這里指定 SORT_STRING 和 SORT_NUMERIC 就有明顯的效果了。我們可以看出,如果是根據(jù)數(shù)字排序,那么結(jié)果就是以數(shù)字內(nèi)容為準(zhǔn)的,如果是根據(jù)字符排序,那么結(jié)果就是以鍵值中的字符串部分為基礎(chǔ)進(jìn)行排序的。
不管是 sort() 還是 asrot() 本質(zhì)上都和普通的 PHP 默認(rèn)提供的 sort() 和 asrot() 函數(shù)一樣的。只是它們多了區(qū)域語言的功能而已。
另外,Collator 對(duì)象中還提供了一個(gè) sortWithSortKeys() 方法,這個(gè)是普通的 PHP 排序函數(shù)中沒有的。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$arr = [ '我' , '是' , '硬' , '核' , '項(xiàng)' , '目' , '經(jīng)' , '理' ]; $coll ->sortWithSortKeys( $arr ); var_dump( $arr ); // array ( // 0 => '核', // 1 => '經(jīng)', // 2 => '理', // 3 => '目', // 4 => '是', // 5 => '我', // 6 => '項(xiàng)', // 7 => '硬', // ) |
它與 sort() 方法是類似的,但使用的是 ucol_getSortKey() 來生成的 ICU 排序鍵,在大型數(shù)組上的速度更快。
ICU 的全稱是 International Components for Unicode ,也就是 Unicode 的國際化組件,它提供了翻譯相關(guān)的功能,也就是我們系統(tǒng)中以及各類編程語言要實(shí)現(xiàn)國際化能力的基礎(chǔ)。
比較
接下來就是字符串的比較,比如說我們都知道,"a" 是比 "A" 要大的,因?yàn)樵?ASC2 碼表中,"A" 是 65 ,"a" 是 97 。當(dāng)然,這只是默認(rèn)情況下的比較,在使用 Collator 對(duì)象的函數(shù)進(jìn)行比較時(shí),則是根據(jù)字典庫中的排序索引進(jìn)行比較的,對(duì)于中文來說,基本上就也是按照拼音的順序來比較了。
1
2
|
var_dump( $coll ->compare( 'Hello' , 'hello' )); // int(1) var_dump( $coll ->compare( '你好' , '您好' )); // int(-1) |
compare() 方法就是用來進(jìn)行比較的,如果兩個(gè)字符串相等,返回的就是 0 ,如果第一個(gè)字符串大于第二個(gè),返回的是 1 ,否則返回的是 -1 。從代碼中,我們可以看出 "Hello" 是大于 "hello" 的,"你好" 是小于 "您好" 的( 因?yàn)?"您" 多了一個(gè) g )。
屬性設(shè)置
Collator 對(duì)象中還可以設(shè)置一些對(duì)象的屬性。
1
2
3
4
5
6
7
8
9
10
11
|
$coll ->setAttribute(Collator::CASE_FIRST, Collator::UPPER_FIRST); var_dump( $coll ->getAttribute(Collator::CASE_FIRST)); // int(25) var_dump( $coll ->compare( 'Hello' , 'hello' )); // int(-1) $coll ->setAttribute(Collator::CASE_FIRST, Collator::LOWER_FIRST); var_dump( $coll ->getAttribute(Collator::CASE_FIRST)); // int(24) var_dump( $coll ->compare( 'Hello' , 'hello' )); // int(1) $coll ->setAttribute(Collator::CASE_FIRST, Collator::OFF); var_dump( $coll ->getAttribute(Collator::CASE_FIRST)); // int(16) var_dump( $coll ->compare( 'Hello' , 'hello' )); // int(1) |
這里我們是為對(duì)象指定 CASE_FIRST 屬性,屬性值可以指定 大寫優(yōu)先、小寫優(yōu)先 之類的,對(duì)于英文字符來說,這個(gè)可以影響排序以及對(duì)比的結(jié)果。
另外,我們還可以通過一個(gè)方法獲得當(dāng)前區(qū)域語言的信息。
1
2
|
var_dump( $coll ->getLocale(Locale::VALID_LOCALE)); // string(10) "zh_Hans_CN" var_dump( $coll ->getLocale(Locale::ACTUAL_LOCALE)); // string(2) "zh" |
這兩個(gè)參數(shù)分別是獲得有效的區(qū)域設(shè)置信息和實(shí)際的區(qū)域信息。
排序信息
當(dāng)然,我們也可以看到具體的排序信息,也就是字符在 Collator 中的編碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var_dump(bin2hex( $coll ->getSortKey( 'Hello' ))); // string(20) "b6b0bebec4010901dc08" var_dump(bin2hex( $coll ->getSortKey( 'hello' ))); // string(18) "b6b0bebec401090109" var_dump(bin2hex( $coll ->getSortKey( '你好' ))); // string(16) "7b9b657301060106" var_dump(bin2hex( $coll ->getSortKey( '您好' ))); // string(16) "7c33657301060106" $coll = collator_create( 'en_US' ); var_dump( $coll ->compare( 'Hello' , 'hello' )); // int(1) var_dump( $coll ->compare( '你好' , '您好' )); // int(-1) var_dump( $coll ->getLocale(Locale::VALID_LOCALE)); // string(5) "en_US" var_dump( $coll ->getLocale(Locale::ACTUAL_LOCALE)); // string(4) "root" var_dump(bin2hex( $coll ->getSortKey( 'Hello' ))); // string(20) "3832404046010901dc08" var_dump(bin2hex( $coll ->getSortKey( 'hello' ))); // string(18) "383240404601090109" var_dump(bin2hex( $coll ->getSortKey( '你好' ))); // string(20) "fb0b8efb649401060106" var_dump(bin2hex( $coll ->getSortKey( '您好' ))); // string(20) "fba5f8fb649401060106" |
可以看出,不用同的區(qū)域語言獲取到的 getSortKey() 排序鍵信息是不同的,不過它們都是以 16進(jìn)制 存儲(chǔ)的,這和默認(rèn)的 ASC2 碼完全不同了。
錯(cuò)誤信息
1
2
3
4
|
$coll = new Collator( 'en_US' );; $coll ->compare( 'y' , 'k' ); var_dump( $coll ->getErrorCode()); // int(0) var_dump( $coll ->getErrorMessage()); // string(12) "U_ZERO_ERROR" |
使用 getErrorCode() 可以獲得錯(cuò)誤碼,使用 getErrorMessage() 可以獲得錯(cuò)誤信息。關(guān)于返回的這個(gè) U_ZERO_ERROR 并沒有查找到相關(guān)的資料,希望懂行的朋友可以回復(fù)說明,大家一起學(xué)習(xí)。
排序規(guī)則強(qiáng)度
另外就是 Collator 對(duì)象就還有一個(gè)排序強(qiáng)度的設(shè)定,不過我測試的效果并沒有體現(xiàn)出來。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
$arr = array ( 'a' , 'à' , 'A' ); $coll = new Collator( 'de_DE' ); $coll ->sort( $arr ); var_dump( $coll ->getStrength()); var_dump( $arr ); // int(2) // array(3) { // [0]=> // string(1) "a" // [1]=> // string(1) "A" // [2]=> // string(2) "à" // } $coll ->setStrength(Collator::IDENTICAL); var_dump( $coll ->getStrength()); // int(15) $coll ->sort( $arr ); var_dump( $arr ); $coll ->setStrength(Collator::QUATERNARY); var_dump( $coll ->getStrength()); // int(3) $coll ->sort( $arr ); var_dump( $arr ); $coll ->setStrength(Collator::PRIMARY); var_dump( $coll ->getStrength()); // int(0) $coll ->sort( $arr ); var_dump( $arr ); $coll ->setStrength(Collator::TERTIARY); var_dump( $coll ->getStrength()); // int(2) $coll ->sort( $arr ); var_dump( $arr ); $coll ->setStrength(Collator::SECONDARY); var_dump( $coll ->getStrength()); // int(1) $coll ->sort( $arr ); var_dump( $arr ); |
在官方文檔的測試代碼的結(jié)果中,指定不同的參數(shù)會(huì)返回不同的排序順序,但我實(shí)際測試的結(jié)果卻全都是一樣的。所以這里就不做講解了,因?yàn)樽约阂矝]搞明白為什么。大家了解一下即可,如果有清楚這方面知識(shí)的朋友也請(qǐng)留言回復(fù)一起學(xué)習(xí)哦!
總結(jié)
很有意思的一個(gè)對(duì)象吧,其實(shí)這個(gè)對(duì)象也是支持面向過程式的函數(shù)寫法的,在示例代碼中也有使用面向過程的方式的調(diào)用的。總體來說,按拼音排序和比較這兩個(gè)功能在實(shí)際的開發(fā)中相信還是有不少用武之地的,大家可以嘗試看看哦!
測試代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202011/source/3.PHP中國際化的字符串比較對(duì)象.php
參考文檔:
https://www.php.net/manual/zh/class.collator.php
到此這篇關(guān)于PHP中國際化的字符串排序和比較對(duì)象的文章就介紹到這了,更多相關(guān)PHP國際化字符串比較對(duì)象內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://segmentfault.com/a/1190000040488896