继:我朝特有需求之《英文字符占 0.5 个,中文字符占 1 个》
之所以写继篇,其实我是来自我检讨的,上一次发表了 《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 协议》,转载必须注明作者和本文链接
推荐文章: