zoukankan      html  css  js  c++  java
  • ThinkSNS+ 是如何计算字符显示长度的

    什么是ThinkSNS+

      ThinkSNS(简称TS),一款全平台综合性社交系统,目前最新版本为ThinkSNS+、ThinkSNS V4 ThinkSNS【简】。

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

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

    ab
    哈
    ?

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

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

    需求规则是  /^[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*$/

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

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

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

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

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

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

    所以,首先我们用:

    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;

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

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

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

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

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

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

    往期研发日记回顾:

    《ThinkSNS+基于 Laravel master 分支【研发日记一】》

    《ThinkSNS+研发中前端的抉择(webpack/Vue)踩坑日记【研发日记二】》

    《基于 Laravel Route 的 ThinkSNS+ Component【研发日记三】》

    《如何做到 Laravel 配置可以网站后台配置【研发日记四】》

    开源代码仓库:

    GitHub:https://github.com/zhiyicx/thinksns-plus(点击star,每日关注开发动态。)

  • 相关阅读:
    Proj THUDBFuzz Paper Reading: The Art, Science, and Engineering of Fuzzing: A Survey
    Proj THUDBFuzz Paper Reading: A systematic review of fuzzing based on machine learning techniques
    9.3 付费代理的使用
    11.1 Charles 的使用
    第十一章 APP 的爬取
    10.2 Cookies 池的搭建
    10.1 模拟登录并爬取 GitHub
    11.5 Appium 爬取微信朋友圈
    11.4 Appium 的基本使用
    11.3 mitmdump 爬取 “得到” App 电子书信息
  • 原文地址:https://www.cnblogs.com/thinkSNS/p/11039482.html
Copyright © 2011-2022 走看看