ThinkSNS+ 是如何计算字符显示长度的

什么是ThinkSNS+

  ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS+、ThinkSNS+ V4、ThinkSNS+【简】。

今天我们来聊一下可能很多人都会头疼的东西:显示长度。

需求是这样的,在字符的显示上,两个英文单词才占一个中文或者其他语言的显示长度。如下:

1
2
3
ab
?

上面排的是两个英文字母,一个汉字,一个Emoji。你会发现,在显示上占的宽度是一致的。一些设计上为了好看也要求有这样的处理。

例如,我们的用户名需求是最多12个非单字节字符或者24个单字节字符的需求也可以混合排的需求,我们写后端不得不处理这样的验证了。

需求规则是  /^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/

在ThinkSNS+中,为了能把这部分验证公用,所以选择使用自定义验证规则。我们先说下计算的实现思路吧!

首先,就算是mb_strlen也没法准确的获取多字节字符和单子节字符混合在一起的长度,网上有个说法,汉字占三个字节,英文数组半角符号占一个字节,所以:

1
(mb_strlen($str) + strleng($str)) / 2

用这个方法可以得到单字节占0.5多字节占1的计算。但是以中文为例,只有两万个汉字才是这种情况,还有六万多汉字是四个,其次,emoji也是四个字节。根本无法准确的计算。

好在在无意间发现一个奇怪的东西str_word_count 这个函数计算非英文单词外是除了符号例如中文就是按照汉字个数算的,emoji也是同理。

发现这个以后,咱们就好办了。我们吧用户名中的 [a-aA-Z0-9_] 剔除掉,单独计算不就是我们要的验证长度了吗?

所以,首先我们用:

1
2
preg_match_all('/[a-zA-Z0-9_]/'$value$single);
$single count($single[0]) / 2;

方式单独计算出单字节字符的显示长度,再用:

1
$double str_word_count(preg_replace('([a-zA-Z0-9_])'''$value));

方式计算出多字节的长度,最后:

1
$length $single $double;

就得出了显示长度,实现了,最后封装成验证规则:

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
Validator::extend('display_length'function ($attribute$valuearray $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 str_word_count(preg_replace('([a-zA-Z0-9_])'''$value));
 
                        // 得出最终计算字符的长度
            $length $single $double;
 
            return $length >= $min && $length <= $max;
});

代码是原型代码,还没有进行优化,之后我们只要按照下面的方式用:

1
2
3
4
$rules = [
    'inputKey' => 'display_length:5'// 表示 0 - 5 显示长度
    ‘inputkey2’ => 'display_length:4,12' // 表示显示长度为 4 - 12
];

现在就很好的解决了这个需求。

我们很乐意,将基于 Laravel 的 ThinkSNS+ 产品开发中的技术解决方案分享给大家,也希望喜欢的朋友能给国内开源产品一点点的支持。

posted @   经管时评  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示