JS字符串截取出现的bug以及解决方式

 更新时间:2022年12月05日 10:16:13   作者:格斗家不爱在外太空沉思  
之前在获取元素属性时,踩了个坑,记录一下,下面这篇文章主要给大家介绍了关于JS字符串截取出现的bug以及解决方式,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

前言

在js中我们对字符串进行一部分截取,可以使用slice()函数截取,也可以直接用substring()函数来截取,但是截取也有可能出bug

const str='小𠮷和小𧨁今天吃了50块钱的KFC'
console.log(str.slice(0,5));

可以在控制台看到,本来应该截取的字符串是'小𠮷和小𧨁'才对,却少了一个字,这是什么原因呢?

js的字符编码

在很早的时候,js使用的编码规范是16位的字符编码(USC-2),规定了每一个字对应16位的空间,16位的空间称为码元,字符串的所有属性和方法(像是 length 属性和 chatAt 方法)都是基于 16 位的码元,但是后来生僻字越来越多,16位的空间不够用了

就把编码方式换成了utf-16,utf-16允许一个文字占用16位的空间也就是一个码元或者32位的空间就是两个码元,一些特殊的文字就占用了两个码元,像'𠮷'和'𧨁'就占用了两个码元

使用码元截取的bug

我们使用的length属性实际上数的是码元的数量,而使用slice()方法截取字符串是根据下标来截取的,下标也是指的码元的下标

比如我们截取'小𠮷'这两个字,将slice()截取的范围改为0到1也就是console.log(str.slice(0,2)), '𠮷'占用了两个码元,slice()只截取到了它第一个码元的值,一个码元形不成文字,这样得到的就不是一个完整的字,而是一个乱码了

使用码点来正确截取字符串

既然使用码元获取不到正确的字符,那就可以使用码点来截取了,什么是码点呢?码点不管你占用多少空间,一个文字就占一个码点,一个码点对应一个码元或者两个码元,使用码点截取就要写一个截取的函数了

我们在字符串的原型对象上新建一个函数,传入一个截取的起始坐标和结束坐标,准备好一个result变量存储最终截取到的结果,和两个代表码元和码点指针的变量

String.prototype.strSlice=function(sStart,sEnd){//截取的起始坐标和结束坐标
  let result='' //截取的结果
  let dIndex=0 //码点的指针
  let yIndex=0 //码元的指针
}

接下来就要不断地向右运行码点和码元的指针进行截取,所以需要一个无限循环,当码点的指针到达了结束的位置或者码元的指针超出了数组的长度就结束循环返回最终截取的结果

while(1){
    if(dIndex>=sEnd || yIndex>=this.length){ //结束循环条件
      break;
    }
    //截取操作
}
return result //返回截取结果

每一次循环就码点和码元移动一次指针,码点直接每次移动1位,但是一个字符会存在两个码元,这样码元和码点就对应不上了,需要根据字符占据的码元数量来移动

在ES6为我们提供了一个函数codePointAt可以得到码点的值,码点的值有可能是16位或者32位的,而一个文字占用16位,如果码点的值超过16位说明这个文字占用了两个码元,我们就可以通过码点的值判断码元的指针应该移动1位或者2位

while(1){
    if(dIndex>=sEnd || yIndex>=this.length){ //结束循环条件
      break;
    }
    //截取操作
    const point=this.codePointAt(yIndex) //获取码点的值
    
    dIndex++ //码点指针每次+1
     yIndex+=point > 0xffff ? 2:1 //判断码点的值是否超过16位,超过占用2个码元,指针+2,没有+1
}
return result //返回截取结果

码点和码元的指针移动已经同步了,对应在同一个文字上,然后就可以截取文字了。当码点的指针大于等于起始坐标就把对应的文字取出来放在result里,不能通过 this[yIndex] 取值,不然还是取的码元对应的值,得通过码点对应的值取出来,在ES6里还提供了一个函数fromCodePoint,按照码点的值恢复这个文字,将文字加到result里就行了

String.prototype.strSlice=function(sStart,sEnd){//截取的起始坐标和结束坐标
  let result='' //截取的结果
  let dIndex=0 //码点的指针
  let yIndex=0 //码元的指针
  while(1){
    if(dIndex>=sEnd || yIndex>=this.length){ //结束循环条件
      break;
    }
    //截取操作
    const point=this.codePointAt(yIndex) //获取码点的值
    if(dIndex>=sStart){
      result+=String.fromCodePoint(point)
    }

    dIndex++
    yIndex+=point > 0xffff ? 2:1 //判断码点的值是否超过16位,超过占用2个码元,指针+2,没有+1
  }
  return result //返回截取结果
}

最后调用strSlice方法,传入截取的起始坐标和结束坐标,截取到的结果也是我们想要的

console.log('截取的结果为:',str.strSlice(0,5));

总结

到此这篇关于JS字符串截取出现的bug以及解决方式的文章就介绍到这了,更多相关JS字符串截取bug内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 妙用Bootstrap的 popover插件实现校验表单提示功能

    妙用Bootstrap的 popover插件实现校验表单提示功能

    最近使用bootstrap开发项目比较多,在表单校验功能中用popover插件实现出错提示功能很方面,下面小编给大家带来了一篇关于Bootstrap的 popover插件实现校验表单提示功能的实现代码,非常不错,感兴趣的朋友一起看看吧
    2016-08-08
  • 微信小程序云开发实现分页刷新获取数据

    微信小程序云开发实现分页刷新获取数据

    这篇文章主要为大家详细介绍了微信小程序云开发实现分页刷新获取数据,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • 浅谈JavaScript工具链不完全指南

    浅谈JavaScript工具链不完全指南

    经过这么多年的发展,JavaScript 早已经不是当年那个不太起眼的脚本语言。如今的 JavaScript 可以说是风光无限,在 Web 前端、移动端、服务端甚至物联网设备上都大展身手,到处都有它的身影。
    2021-05-05
  • js实现简单省市区三级选择联级

    js实现简单省市区三级选择联级

    这篇文章主要介绍了js实现简单省市区三级选择联级,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • Bootstrap进度条组件知识详解

    Bootstrap进度条组件知识详解

    在网页中,经常见到进度条效果,那么这些个性的进度条组件效果是怎么实现的呢,下面脚本之家小编给大家分享Bootstrap进度条组件知识详解,感兴趣的朋友要求学习吧
    2016-05-05
  • js局部刷新页面时间具体实现

    js局部刷新页面时间具体实现

    这篇文章介绍了js局部刷新页面时间具体实现,需要的朋友可以参考一下
    2013-07-07
  • uniapp开发h5项目引入第三方js(sdk)两种方法

    uniapp开发h5项目引入第三方js(sdk)两种方法

    这篇文章主要给大家介绍了关于uniapp开发h5项目引入第三方js(sdk)的两种方法,在Uniapp中引入JS文件是一项常见的操作,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-02-02
  • js读取cookie方法总结

    js读取cookie方法总结

    这篇文章主要介绍了js读取cookie方法,实例总结了四种常用的读取方法,包含了对cookie数据的分割与遍历操作,是非常实用的技巧,需要的朋友可以参考下
    2014-10-10
  • 自定义require函数让浏览器按需加载Js文件

    自定义require函数让浏览器按需加载Js文件

    可能很多人看到这个题目就会想到LABjs、RequireJS、SeaJS... 这些库,但无奈小编没用过这些库,什么 AMD 、CMD 哪来那么多术语... 前端的库太多了,要看各种乱七八糟的文档,好难啊,还不如自己写一个库呢。于是就有了这文章,有需要的朋友们下面来一起学习学习吧。
    2016-11-11
  • javascript实现打砖块小游戏(附完整源码)

    javascript实现打砖块小游戏(附完整源码)

    这篇文章主要为大家详细介绍了javascript实现打砖块小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09

最新评论