之所以寫繼篇,其實我是來自我檢討的,上一次發表了 《ThinkSNS+ 是如何計算字元顯示長度的(使用 Laravel 自定義驗證規則)》 後,下面有一個網友多方測試告訴我說 str_word_count
是有問題的,但是我的環境下確實成功的,所以一直在想一個相容性更高的方法。
這短時間一直在開發 ThinkSNS+ 的支付功能,所以一直沒時間看,今天上午可能沒有什麼感覺寫程式碼,乾脆就來像一個相容性更好的計算方法。
需求
重新說下需求,在我天朝 PM 經常會提一種要求,就是例如 一個使用者名稱做多輸入 12 個漢字,但是英文可以輸入 24 個,混排也要滿足這個規則,也就是 單位元組字元佔 0.5 多子節字元佔 1這樣的計算。
解決
閒下來的時候看了上篇文字發的計演算法法,其實是沒什麼問題的,就是相容性不好,而且寫那個方法的時候也是想多了,根本沒有那麼複雜,我們看上一篇中計算多子節的方法:
$double = str_word_count(preg_replace('([a-zA-Z0-9_])', '', $value));
計算方法是剔除我們需求中允許的單位元組,然後通過 str_word_count
來獲取多子節的個數,其實這個函式是可以獲取到的,但是部分系統下是不會成功的,其實還有一個函式就可以直接獲取多子節的個數 mb_strlen
修改後如下:
第一想法是,當時傻逼了。
$double = mb_strlen(preg_replace('([a-zA-Z0-9_])', '', $str));
然後我們就可以正確完成這個需求了,最終實現的 Laravel 驗證規則如下:
// 新增長度規則
Validator::extend('display_length', function ($attribute, $value, array $parameters) {
if (empty($parameters)) {
throw new \InvalidArgumentException('Parameters must be passed');
}
$min = 0;
if (count($parameters) === 1) {
list($max) = $parameters;
} elseif (count($parameters) >= 2) {
list($min, $max) = $parameters;
}
if (! isset($max) || $max < $min) {
throw new \InvalidArgumentException('The parameters passed are incorrect');
}
// 計算單位元組.
preg_match_all('/[a-zA-Z0-9_]/', $value, $single);
$single = count($single[0]) / 2;
// 多子節長度.
$double = mb_strlen(preg_replace('([a-zA-Z0-9_])', '', $value));
$length = $single + $double;
return $length >= $min && $length <= $max;
});
laravel 通過上面的規則,可以在表單驗證規則中直接驗證了,還支援傳入最小值和最大值。
上面的程式碼都是來自於 基於 Laravel 開發的開源程式 ThinkSNS+ 中,ThinkSNS+ 採用 apache-2.0 協議開源,我相信可以作為很多 Laravel 學習者的學習程式之一。
喜歡的話幫忙點個 star ,開源不易,感謝大家的支援。
GitHub: https://github.com/zhiyicx/thinksns-plus
本作品採用《CC 協議》,轉載必須註明作者和本文連結
Seven 的程式碼太渣,歡迎關注我的新擴充包 medz/cors 解決 PHP 專案程式設定跨域需求。