先说下需求吧,这是一个挺操蛋的需求,大多数 PHPer 接到真需求就不想满足它,嗯,国内的 PM 经常会提的,就是用户的用户名或者发表文章的内容或者标题,两个单字节字符才能算一个长度单位。
例如:用户名要求最长 12 位,如果输入英文,可以输入 24 位。开心吧?在 PHP 中 strlen
是按照「字节」计算的,而 mb_strlen
是完整完整字符族算的,都无法满足。
因为 ThinkSNS+ 是使用 Laravel 开发的,所以在注册、登录等操作的时候验证用户名字段都应该使用「表单验证」这就涉及到规则的拓展,很明显,又长度限制和字符范围限制,所以应该拓展两个规则,分别是:
但是长度不只是在用户名场景使用,所以最后修改为「显示长度规则」
在 AppServiceProvider
的 boot
方法中增加规则。
Validator::extend('username', function ($attribute, $value) {
return preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $value);
});
这是我们定的用户名规则,只是不允许非数字开头,也不允许出现特殊字符。
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;
});
你可能觉额长度这么复杂?不,其实不复杂,使用上:
$rules = [
'foo' => 'display_length:12', // 最长 12 显示长度
'bar' => 'display_length:4,12', // 显示长度在 4 - 12 之间
];
其实一开始想了很多方法,都不理想,例如「转 GBK 」、「(strlen + mb_strlen) / 4 」等,转 GBK 的确也能正确的计算出来,到那时通过测试后发现,转码所消耗的性能比这个方法要更耗性能。字符方法只对中文两万多个常用汉字有用,而且我们希望兼容全球的所有语言以及 emoji。
最后我们想出来了将单字节字符提取出来单独计算,而多子节字符按照正常字符族计算不就好了吗?
首先提出单字节计算:
preg_match_all('/[a-zA-Z0-9_]/', $value, $single);
$single = count($single[0]) / 2;
这样之后,每一个单字节字符都按照 0.5 的长度进行计算了。
最后将单字节删除用 mb_strlen
计算除字符族:
$double = mb_strlen(preg_replace('([a-zA-Z0-9_])', '', $value));
这样我们就满足了「两个英文=一个中文」的需求了。
上面的打码都是来自于我们团队正在开发的国内开源产品「 ThinkSNS+」,开源不易,大家帮忙点一个 Star 呗!!!
ThinkSNS+ 是基于 Latavel 而开发,里面涉及了很多 Laravel 知识点,个人觉得也可以作为 PHPer 学习使用 Laravel 开发应用的一个范例。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.