1. 程式人生 > 程式設計 >PHP中國際化的字串排序和比較物件詳解

PHP中國際化的字串排序和比較物件詳解

目錄
  • 前言
  • 排序
  • 比較
  • 屬性設定
  • 排序資訊
  • 錯誤資訊
  • 排序規則強度
  • 總結

前言

在 中,國際化的功能非常豐富,包括很多我們可能都不知道的東西其實都非常有用,比如說今天要介紹的這一系列的字元排序和比較的功能。

排序

正常來說,如果我們對陣列中的字元進行排序,按照的是字元的 ASC2 表的順序進行排列,如果是英文還好,但對於中文的話,排序出來的結果會是非常懵逼的。

$arr = ['我','是','硬','核','項','目','經','理'];
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) "經"
//     [7]=>
//     string(3) "項"
//   }

按照我們的習慣會以中文的拼音來對漢字進行排序,這個時候往往大家都會選擇自己寫排序的演算法或者去找合適的 Composer 包。其實,PHP 中已經為我們準備了一個物件就是用來處理這類問題的。

$coll = new Collator( 'zh_CN' );

$coll->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) "項"
//     [7]=>
//     string(3) "硬"
//   }

沒錯,正是這個 Collator 類。它在例項化的時候需要指定當前的區域,比如我們指定為 zh_CN ,也就是中文字元區域,這時候再使用它的 sort() 方法就可以完成對中文字元的拼音排序。

$coll->sort($arr,Collator::SORT_NUMERIC );
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) "項"
//     [7]=>
//     string(3) "硬"
//   }

$coll->sort($arr,Collator::SORT_STRING );
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) "項"
//     [7]=>
//     string(3) "硬"
//www.cppcns.com
}

Collator 物件的 sort() 方法還支援第二個引數,用於指定當前的排序是按照字元還是數字格式進行排序。對於純中文的內容來說,這個沒有什麼區別。

除了www.cppcns.com sort() 方法之外,它還有一個 asort() 方法,就和普通的 asort() 函式一樣的功能,只不過它也是支援不同的區域語言的。

$arr = [
    'a' => '100','b' => '7','c' => '50'
];
$coll->awww.cppcns.comsort($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(3ViZhCtc) {
//     ["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',//     '的' => '7',//   )

asrot() 方法是根據鍵和值一起進行排序的,所以在這裡指定 SORT_STRING 和 SORT_NUMERIC 就有明顯的效果了。我們可以看出,如果是根據數字排序,那麼結果就是以數字內容為準的,如果是根據字元排序,那麼結果就是以鍵值中的字串部分為基礎進行排序的。

不管是 sort() 還是 asrot() 本質上都和普通的 PHP 預設提供的 sort() 和 asrot() 函式一樣的。只是它們多了區域語言的功能而已。

另外,Collator 物件中還提供了一個 sortWithSortKeys() 方法,這個是普通的 PHP 排序函式中沒有的。

$arr = ['我','理'];
$coll->sortWithSortKeys($arr);
var_dump( $arr );
// array (
//     0 => '核',//     1 => '經',//     2 => '理',//     3 => '目',//     4 => '是',//     5 => '我',//     6 => '項',//     7 => '硬',//   )

它與 sort() 方法是類似的,但使用的是 ucol_getSortKey() 來生成的 ICU 排序鍵,在大型陣列上的速度更快。

ICU 的全稱是 International Components for Unicode ,也就是 Unicode 的國際化元件,它提供了翻譯相關的功能,也就是我們系統中以及各類語言要實現國際化能力的基礎。

比較

接下來就是字串的比較,比如說我們都知道,"a" 是比 "A" 要大的,因為在 ASC2 碼錶中,"A" 是 65 ,"a" 是 97 。當然,這只是預設情況下的比較,在使用 Collator 物件的函式進行比較時,則是根據字典庫中的排序索引進行比較的,對於中文來說,基本上就也是按照拼音的順序來比較了。

var_dump($coll->compare('Hello','hello')); // int(1)
var_dump($coll->compare('你好','您好')); // int(-1)

compare() 方法就是用來進行比較的,如果兩個字串相等,返回的就是 0 ,如果第一個字串大於第二個,返回的是 1 ,否則返回的是 -1 。從程式碼中,我們可以看出 "Hello" 是大於 "hello" 的,"你好" 是小於 "您好" 的( 因為 "您" 多了一個 g )。

屬性設定

Collator 物件中還可以設定一些物件的屬性。

$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)

這裡我們是為物件指定 CASE_FIRST 屬性,屬性值可以指定 大寫優先、小寫優先 之類的,對於英文字元來說,這個可以影響排序以及對比的結果。

另外,我們還可以通過一個方法獲得當前區域語言的資訊。

var_dump($coll->getLocale(Locale::VALID_LOCALE)); // string(10) "zh_Hans_CN"
var_dump($coll->getLocale(Locale::ACTUAL_LOCALE)); // string(2) "zh"

這兩個引數分別是獲得有效的區域設定資訊和實際的區域資訊。

排序資訊

當然,我們也可以看到具體的排序資訊,也就是字元在 Collator 中的編碼。

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','您好')); // 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"

可以看出,不用同的區域語言獲取到的 getSortKey() 排序鍵資訊是不同的,不過它們都是以 16進位制 儲存的,這和預設的 ASC2 碼完全不同了。

錯誤資訊

$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() 可以獲得錯誤碼,使用 getErrorMessage() 可以獲得錯誤資訊。關於返回的這個 U_ZERO_ERROR 並沒有查詢到相關的資料,希望懂行的朋友可以回覆說明,大家一起學習。

排序規則強度

另外就是 Collator 物件就還有一個排序強度的設定,不過我測試的效果並沒有體現出來。

$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 );

在官方文件的測試程式碼的結果中,指定不同的引數會返回不同的排序順序,但我實際測試的結果卻全都是一樣的。所以這裡就不做講解了,因為自己也沒搞明白為什麼。大家瞭解一下即可,如果有清楚這方面知識的朋友也請留言回覆一起學習哦!

總結

很有意思的一個物件吧,其實這個物件也是支援面向過程式的函式寫法的,在示例程式碼中也有使用面向過程的方式的呼叫的。總體來說,按拼音排序和比較這兩個功能在實際的開發中相信還是有不少用武之地的,大家可以嘗試看看哦!

測試程式碼:

https://.com/zhangyue0503/dev-blog/blob/master/php/202011/source/3.PHP中國際化的字串比較物件.php

參考文件:

https://www.php.net/manual/zh/class.collator.php

到此這篇關於PHP中國際化的字串排序和比較物件的文章就介紹到這了,更多相關PHP國際化字串比較物件內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!