JS字符串的截取出现的bug

news2025/1/22 9:05:47

前言

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

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/151703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ESP-IDF:数组为空异常处理例程

1.需要开启对ESP-IDF 中的 C 异常的支持。 默认情况下禁用对 ESP-IDF 中的 C 异常的支持,但可以使用 CONFIG_CXX_EXCEPTIONS 选项启用. 如果禁用对 ESP-IDF中的 C 异常的支持这样编译例程会报错: error: exception handling disabled, use -fexceptions to enable…

node.js中的文件读取写入操作

fs文件系统模块 什么是fs文件系统模块 fs模块是node.js官方提供的、操作文件的模块。通过fs模块可以实现对文件的读取以及写入操作。 例如: fs.readFile():用于读取指定文件的文件内容fs.writeFile():用于向指定的文件写入内容 引入fs模块&#xff…

[2023] NAND闪存及控制器的市场趋势

一、NAND闪存市场分析据欧洲知名半导体分析机构Yole发布的报告显示,2020年起,NAND闪存市场发展趋势保持稳定增长,2021年,NAND闪存市场份额达到了近670亿美元(见图1),同年,NAND闪存总…

使用 Vagrant 对 VirtualBox 虚拟机磁盘扩容

使用Vagrant 对 VirtualBox 磁盘扩容 Vagrant 下载地址: https://www.vagrantup.com/downloads.html Vagrant版本 2.3.4 VirtualBox版本:7.0.4 1、在初次使用 Vagrant init 创建 VirtualBox 虚拟机时,会创建一个 Vagrantfile 文件 2、在 Vagrantfile…

CAS:60842-46-8;葡聚糖-荧光素;Dextran-FITC

Dextran-FITC、葡聚糖-荧光素、(葡聚糖-FITC) CAS NO: 60842-46-8 英文名称:: Dextran(3,6dihydroxy-3-oxospiro(isobenzofuran-1(3H],9-[9H]xanthen]-5(or 6]-yl]carbamothioate, average Mw of approximately 分子量&#xf…

java 微服务之docker基础入门 docker部署 镜像相关命令 容器命令 数据卷 DockerCompose Docker镜像仓库

初识Docker 项目部署的问题 什么是Docker 不同环境的操作系统不同,Docker如何解决?我们先来了解下操作系统结构 Docker与虚拟机 虚拟机是在一个系统内,运行另外一个系统 镜像和容器 镜像(Image):Docker将…

基于STM32 STC15和SU-03T离线语音模块的智能语音自拍器设计

一. 系统设计及框图 现在的自拍系统有很多是蓝牙控制的,我们这次介绍的是使用语音控制的拍照系统。 本系统通过MCU产生20kHZ左右的频率驱动蜂鸣器(占空比为50%即可),手机APP收到此特定频率的信号后会执行相应的拍照或切换镜头的…

Spring 响应式编程,真香!!!

一、前言 响应式编程是啥?为啥要有响应式编程?响应式流的核心机制是什么?Spring 响应式编程能解决我们平时开发的什么痛点?Spring 响应式编程有哪些应用场景?Spring 响应式编程未来的趋势如何? 开篇六连问…

必要条件和充分条件与分析问题的方法

作为一名软件工程师,大部分的工作时间都是在解决各种问题中度过的,相信大部分的工程师都有类似的感受。这些问题发生在不同的技术领域,不同的技术方向,不同的模块,甚至不同的环境下,不一而足,就…

韩顺平老师的Linux基础学习笔记 (下)

Linux学习笔记 前言:本系列笔记的参考由 2021韩顺平 一周学会Linux 总结而成,希望能给学习Linux的同学一些帮助。也感谢韩老师录制的视频给我带来了非常巨大的收获! 目录: 韩顺平老师的Linux基础学习笔记 (上)韩顺平老师的Linu…

swagger2 介绍+注解说明

简介: 为什么要用swagger,我的理由是方便,作为后端开放人员,最烦的事就是自己写接口文档和前端交互是不是需要各种参数很繁琐,项目集成swagger后就能自动生成接口文档,做到前端、后端联调接口文档的及时性和便利性。 …

Eureka与Nacos的区别

Eureka 工作原理图 Nacos工作原理图 Eureka与Nacos相同点 都支持服务注册和服务拉取。 都支持服务提供者心跳方式做健康检测。 Eureka与Nacos区别 Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式 临时实例心跳…

理解Java的线程安全问题

目录 目录 举例:三个窗口卖票 运行结果:出现重票 如何解决? 方式一:同步代码块,第一个例子 运行结果: 改进: 运行结果: 方法一:同步代码块的第二个例子。把锁和ti…

使用opencv进行脸部识别

1.读取人脸部图片 引入需要的库,并读取人脸的图片 import cv2 import matplotlib.pyplot as plt import numpy as np# 定义t2s函数,方便查看是否对图片进行RGB通道转换 def t2s(img):return cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 读取图片 img cv2.…

10个PMP冷知识,项目经理看完都说长见识

早上好,我是老原。每次聊起考证啊,我内心总是充满遗憾——毕竟现在的市场情况,让很多项目经理对考证都不看好。但是啊,这群吹证书无用论的小友,总让我想起前几年吹学习无用论的时候,多么的异曲同工&#xf…

PageHelper分页规则

1.问题 1.1.PageHelper先开启分页&#xff0c;后对list数据操作 Overridepublic PageInfo<HdQueryVo> getRecordsByView(int pageNo, int pageSize) {PageHelper.startPage(pageNo,pageSize);List<HdQueryVo> hdQueryVosByView actionMapper.getActionByView();…

TP6(thinkphp6)队列与延时队列

安装 在此我就不再略过TP6的项目创建过程了&#xff0c;大致就是安装composer工具&#xff0c;安装成功以后&#xff0c;再使用composer去创建项目即可。 think-queue 安装 composer require topthink/think-queue 项目中添加驱动配置 我们需要在安装好的config下找到 queu…

SAP工作流任务

前言 灵活工作流沿用的传统工作流的活动节点&#xff0c;只是不再体现在流程图上&#xff0c;工作流的活动根据是否需要代理人可以分为两类&#xff0c;一类是自动后台处理的步骤&#xff0c;另外一类是需要代理人处理的步骤&#xff08;一般为决策节点&#xff09;&#xff0c…

线程通信例子

目录 线程通信的例子&#xff1a;使用两个线程打印1-100。线程1&#xff0c;线程2&#xff0c;交替打印 涉及的3个方法&#xff1a; 运行结果&#xff1a; 把锁改为其他对象 运行结果报错&#xff1a; 改进&#xff0c;把notify和wait的调用者改为obj sleep()和wait()的…

【数据结构】—— Java实现单链表

Java实现单链表一、一链表的概念及结构二、头节点与头指针的异同三、代码实现一、一链表的概念及结构 链表是一种物理存储结构上非连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。 注意&#xff1a; 从上图可以看出&#xff0c;链式结构在逻…