JS字符串的截取出现的bug

JS字符串的截取出现的bug前言 在js中我们对字符串进行一部分截取,可以使用slice()函数截取,也可以直接用substring()函数来截取,但是截取也有可能出bug 可以在控制台看到,本来应该截取的字符串是’小𠮷和小𧨁’

前言

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

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

代码100分

image.png

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

js的字符编码

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

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

使用码元截取的bug

image.png

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

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

image.png

1670046418569.png

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

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

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

代码100分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位,但是一个字符会存在两个码元,这样码元和码点就对应不上了,需要根据字符占据的码元数量来移动

image.png

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

代码100分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里就行了

image.png

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));

image.png

本文正在参加「金石计划 . 瓜分6万现金大奖」

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/11315.html

(0)
上一篇 2023-03-02
下一篇 2023-03-02

相关推荐

  • Windows Logstash同步 Sqlserver 到Elasticsearch[亲测有效]

    Windows Logstash同步 Sqlserver 到Elasticsearch[亲测有效]
    1下载与Elasticsearch对应版本Logstash7.13.2 与数据库驱动JDBC 下载地址:https://artifacts.elastic….

    2023-04-19
    144
  • 时序数据库 Apache-IoTDB 源码解析之文件数据块(四)[通俗易懂]

    时序数据库 Apache-IoTDB 源码解析之文件数据块(四)[通俗易懂]上一章聊到行式存储、列式存储的基本概念,并介绍了 TsFile 是如何存储数据以及基本概念。详情请见: 时序数据库 Apache-IoTDB 源码解析之文件格式简介(三) 打一波广告,欢迎大家访问I…

    2023-01-27
    153
  • anaconda虚拟环境安装的包存储路径

    anaconda虚拟环境安装的包存储路径Python是一种功能强大的编程语言,越来越受到程序员的欢迎。存在的问题是,在同一时间需要使用不同的库,并在应用程序中使用它们。为了解决这个问题,Anaconda发明了虚拟环境。当你创建虚拟环境时,它是独立的,可以拥有自己的Python版本、包和库。当你在环境中安装新的包时,只有该环境才会受到影响。这使得在不同的环境中使用各种Python版本和库变得异常容易。

    2024-09-13
    24
  • Python实现字符串和列表的转换

    Python实现字符串和列表的转换在Python中,字符串和列表是两种不同的数据类型。字符串是由一串字符组成的,而列表是由多个元素组成的序列。字符串是不可变的,即无法在原有字符串上进行修改,而列表可以被修改。

    2024-07-08
    40
  • 浅谈Mysql重置密码「建议收藏」

    浅谈Mysql重置密码「建议收藏」新手刚开始用MySQL的时候可能会很容易忘记登录密码,下面说一下如何重置和修改密码 第一种方法:直接在命令行窗口操作停止服务器mysql(这是重点:直接停止)打开CMD 在命令行窗口输入MySQL安装

    2022-12-27
    135
  • 一站式Kafka平台解决方案——KafkaCenter

    一站式Kafka平台解决方案——KafkaCenterKafkaCenter是什么 KafkaCenter是一个针对Kafka的一站式,解决方案。用于Kafka集群的维护与管理,生产者和消费者的监控,以及Kafka部分生态组件的使用。 对于Kafka的平

    2023-02-28
    146
  • Python中的数组:优化数据结构存储和处理

    Python中的数组:优化数据结构存储和处理Python中的数据结构list可以很方便地存储各种类型的数据,但是其本身是一个动态数组,因此在进行大量的插入和删除操作时,效率会受到影响。此时,可以考虑使用array模块,将数据存储在一个连续且类型相同的内存块中,可以在某些情况下提升处理效率。

    2023-12-20
    106
  • Python数组详解

    Python数组详解Python数据类型有许多种,其中之一是数组。数组是一个有序、可变序列,可以容纳任意类型的数据。Python数组的元素可以是数字、字符串、布尔值等,也可以是其他数组或容器类型。

    2024-07-27
    38

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注