美文网首页
计算和截取指定字符串的UTF-8字节数

计算和截取指定字符串的UTF-8字节数

作者: 躺在家里干活 | 来源:发表于2019-08-28 18:20 被阅读0次

    由于特殊需求,需要限制输入框内容的长度,但是该长度并不是普通的字数长度而是UTF-8的字节数

    UTF-8编码下 字节数

    占2个字节的:〇
    占3个字节的:基本等同于GBK,含21000多个汉字
    占4个字节的:中日韩超大字符集里面的汉字,有5万多个
    一个utf8数字占1个字节
    一个utf8英文字母占1个字节

    Unicode码

    1个字节:Unicode码为0 - 127
    2个字节:Unicode码为128 - 2047
    3个字节:Unicode码为2048 - 0xFFFF
    4个字节:Unicode码为65536 - 0x1FFFFF
    5个字节:Unicode码为0x200000 - 0x3FFFFFF
    6个字节:Unicode码为0x4000000 - 0x7FFFFFFF

    计算指定字符串的字节数

    function computeByteSize(str){
      for (var i=0,byte=0; i < str.length; i++) {
        var charCode = str.charCodeAt(i);
        if (0 <= charCode && charCode <= 0x7f) {
          byte += 1;
        } else if (128 <= charCode && charCode <= 0x7ff) {
          byte += 2;
        } else if (2048 <= charCode && charCode <= 0xffff) {
          byte += 3;
        } else if (65536 < charCode && charCode <= 0x1FFFFF) {
          byte += 4;
        } else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
          byte += 5;
        } else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
          byte += 6;
        }
      }
      return byte
    }
    
    //es6写法
    function computeByteSize(str) {
      let byte=0;
      for (const chr of str) {
        //ES6提供了codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点
        //能正确地识别“?”,返回了它的十进制码点 134071(即十六进制的20BB7)
        let charCode = chr.codePointAt(0)
        if(0 <= charCode && charCode <= 0x7f) {
          byte += 1;
        } else if (128 <= charCode && charCode <= 0x7ff) {
          byte += 2;
        } else if (2048 <= charCode && charCode <= 0xffff) {
          byte += 3;
        } else if (65536 < charCode && charCode <= 0x1FFFFF) {
          byte += 4;
        } else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
          byte += 5;
        } else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
          byte += 6;
        }
      }
      return byte
    }
    

    截取指定字节数的字符串

    function cutStr(str,L){
      for (var i=0,byte=0,result=''; i < str.length; i++) {
         var chr = str.charAt(i);
         var charCode = str.charCodeAt(i);
        if (0 <= charCode && charCode <= 0x7f) {
          byte += 1;
        } else if (128 <= charCode && charCode <= 0x7ff) {
          byte += 2;
        } else if (2048 <= charCode && charCode <= 0xffff) {
          byte += 3;
        } else if (65536 < charCode && code <= 0x1FFFFF) {
          byte += 4;
        } else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
          byte += 5;
        } else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
          byte += 6;
        }
        // 当加上当前字符以后,如果总字节长度小于等于L,则将当前字符真实的+在result后
        if(byte<=L){
          result += chr;
        }else{
          return result;
        }
      }
    }
    
    //es6 写法
    function cutStr(str, L) {
      let byte=0;
      let result='';
      for(let chr of str){
        let charCode = chr.codePointAt(0)
        if (0 <= charCode && charCode <= 0x7f) {
          byte += 1;
        } else if (128 <= charCode && charCode <= 0x7ff) {
          byte += 2;
        } else if (2048 <= charCode && charCode <= 0xffff) {
          byte += 3;
        } else if (65536 < charCode && charCode <= 0x1FFFFF) {
          byte += 4;
        } else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
          byte += 5;
        } else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
          byte += 6;
        }
        // 当加上当前字符以后,如果总字节长度小于等于L,则将当前字符真实的+在result后
        if (byte <= L) {
          result += chr;
        } else {
          return result;
        }
      }
    }
    

    应用demo

    <textarea></textarea>
    <div class="number"></div>
    <script type="text/javascript" src="js/jquery-3.2.1.js"></script>
    <script type="text/javascript">
    $(function(){
      //及时监听文本框内容的变化
      $("textarea").bind('input propertychange',function(){
        var str = $(this).val()
        var len = computeByteSize(str)
        if(len>256){
          $(this).val(cutStr(str,256))
        }else{
          $('.number').html(len)
        }
      });
    })
    </script>
    

    但是目前截取字符串存在一些bug,如果直接复制一段中文内容到文本框,复制的内容超过限制的字节数,则会造成number的内容出错。而且如果输入的为中文,因为一个中文为3个字节数,一个拼音为一个字节数。所以也会出错。有可能造成最后的中文无法显示

    注:汉字“?”(注意,这个字不是“吉祥”的“吉”)的码点是0x20BB7,UTF-16 编码为0xD842 0xDFB7(十进制为55362、57271),需要4个字节储存。对于这种4个字节的字符,JavaScript 不能正确处理,字符串长度会误判为2,而且charAt方法无法读取整个字符,charCodeAt方法只能分别返回前两个字节和后两个字节的值。因此ES6 提供了codePointAt方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。codePointAt 方法在第一个字符上,正确地识别了“?”,返回了它的十进制码点 134071(即十六进制的20BB7)

    我的个人博客,有空来坐坐

    相关文章

      网友评论

          本文标题:计算和截取指定字符串的UTF-8字节数

          本文链接:https://www.haomeiwen.com/subject/jwimectx.html