欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS字符串截取出現(xiàn)的bug以及解決方式

 更新時(shí)間:2022年12月05日 10:16:13   作者:格斗家不愛(ài)在外太空沉思  
之前在獲取元素屬性時(shí),踩了個(gè)坑,記錄一下,下面這篇文章主要給大家介紹了關(guān)于JS字符串截取出現(xiàn)的bug以及解決方式,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

在js中我們對(duì)字符串進(jìn)行一部分截取,可以使用slice()函數(shù)截取,也可以直接用substring()函數(shù)來(lái)截取,但是截取也有可能出bug

const str='小??和小??今天吃了50塊錢的KFC'
console.log(str.slice(0,5));

可以在控制臺(tái)看到,本來(lái)應(yīng)該截取的字符串是'小??和小??'才對(duì),卻少了一個(gè)字,這是什么原因呢?

js的字符編碼

在很早的時(shí)候,js使用的編碼規(guī)范是16位的字符編碼(USC-2),規(guī)定了每一個(gè)字對(duì)應(yīng)16位的空間,16位的空間稱為碼元,字符串的所有屬性和方法(像是 length 屬性和 chatAt 方法)都是基于 16 位的碼元,但是后來(lái)生僻字越來(lái)越多,16位的空間不夠用了

就把編碼方式換成了utf-16,utf-16允許一個(gè)文字占用16位的空間也就是一個(gè)碼元或者32位的空間就是兩個(gè)碼元,一些特殊的文字就占用了兩個(gè)碼元,像'??'和'??'就占用了兩個(gè)碼元

使用碼元截取的bug

我們使用的length屬性實(shí)際上數(shù)的是碼元的數(shù)量,而使用slice()方法截取字符串是根據(jù)下標(biāo)來(lái)截取的,下標(biāo)也是指的碼元的下標(biāo)

比如我們截取'小??'這兩個(gè)字,將slice()截取的范圍改為0到1也就是console.log(str.slice(0,2)), '??'占用了兩個(gè)碼元,slice()只截取到了它第一個(gè)碼元的值,一個(gè)碼元形不成文字,這樣得到的就不是一個(gè)完整的字,而是一個(gè)亂碼了

使用碼點(diǎn)來(lái)正確截取字符串

既然使用碼元獲取不到正確的字符,那就可以使用碼點(diǎn)來(lái)截取了,什么是碼點(diǎn)呢?碼點(diǎn)不管你占用多少空間,一個(gè)文字就占一個(gè)碼點(diǎn),一個(gè)碼點(diǎn)對(duì)應(yīng)一個(gè)碼元或者兩個(gè)碼元,使用碼點(diǎn)截取就要寫一個(gè)截取的函數(shù)了

我們?cè)谧址脑蛯?duì)象上新建一個(gè)函數(shù),傳入一個(gè)截取的起始坐標(biāo)和結(jié)束坐標(biāo),準(zhǔn)備好一個(gè)result變量存儲(chǔ)最終截取到的結(jié)果,和兩個(gè)代表碼元和碼點(diǎn)指針的變量

String.prototype.strSlice=function(sStart,sEnd){//截取的起始坐標(biāo)和結(jié)束坐標(biāo)
  let result='' //截取的結(jié)果
  let dIndex=0 //碼點(diǎn)的指針
  let yIndex=0 //碼元的指針
}

接下來(lái)就要不斷地向右運(yùn)行碼點(diǎn)和碼元的指針進(jìn)行截取,所以需要一個(gè)無(wú)限循環(huán),當(dāng)碼點(diǎn)的指針到達(dá)了結(jié)束的位置或者碼元的指針超出了數(shù)組的長(zhǎng)度就結(jié)束循環(huán)返回最終截取的結(jié)果

while(1){
    if(dIndex>=sEnd || yIndex>=this.length){ //結(jié)束循環(huán)條件
      break;
    }
    //截取操作
}
return result //返回截取結(jié)果

每一次循環(huán)就碼點(diǎn)和碼元移動(dòng)一次指針,碼點(diǎn)直接每次移動(dòng)1位,但是一個(gè)字符會(huì)存在兩個(gè)碼元,這樣碼元和碼點(diǎn)就對(duì)應(yīng)不上了,需要根據(jù)字符占據(jù)的碼元數(shù)量來(lái)移動(dòng)

在ES6為我們提供了一個(gè)函數(shù)codePointAt可以得到碼點(diǎn)的值,碼點(diǎn)的值有可能是16位或者32位的,而一個(gè)文字占用16位,如果碼點(diǎn)的值超過(guò)16位說(shuō)明這個(gè)文字占用了兩個(gè)碼元,我們就可以通過(guò)碼點(diǎn)的值判斷碼元的指針應(yīng)該移動(dòng)1位或者2位

while(1){
    if(dIndex>=sEnd || yIndex>=this.length){ //結(jié)束循環(huán)條件
      break;
    }
    //截取操作
    const point=this.codePointAt(yIndex) //獲取碼點(diǎn)的值
    
    dIndex++ //碼點(diǎn)指針每次+1
     yIndex+=point > 0xffff ? 2:1 //判斷碼點(diǎn)的值是否超過(guò)16位,超過(guò)占用2個(gè)碼元,指針+2,沒(méi)有+1
}
return result //返回截取結(jié)果

碼點(diǎn)和碼元的指針移動(dòng)已經(jīng)同步了,對(duì)應(yīng)在同一個(gè)文字上,然后就可以截取文字了。當(dāng)碼點(diǎn)的指針大于等于起始坐標(biāo)就把對(duì)應(yīng)的文字取出來(lái)放在result里,不能通過(guò) this[yIndex] 取值,不然還是取的碼元對(duì)應(yīng)的值,得通過(guò)碼點(diǎn)對(duì)應(yīng)的值取出來(lái),在ES6里還提供了一個(gè)函數(shù)fromCodePoint,按照碼點(diǎn)的值恢復(fù)這個(gè)文字,將文字加到result里就行了

String.prototype.strSlice=function(sStart,sEnd){//截取的起始坐標(biāo)和結(jié)束坐標(biāo)
  let result='' //截取的結(jié)果
  let dIndex=0 //碼點(diǎn)的指針
  let yIndex=0 //碼元的指針
  while(1){
    if(dIndex>=sEnd || yIndex>=this.length){ //結(jié)束循環(huán)條件
      break;
    }
    //截取操作
    const point=this.codePointAt(yIndex) //獲取碼點(diǎn)的值
    if(dIndex>=sStart){
      result+=String.fromCodePoint(point)
    }

    dIndex++
    yIndex+=point > 0xffff ? 2:1 //判斷碼點(diǎn)的值是否超過(guò)16位,超過(guò)占用2個(gè)碼元,指針+2,沒(méi)有+1
  }
  return result //返回截取結(jié)果
}

最后調(diào)用strSlice方法,傳入截取的起始坐標(biāo)和結(jié)束坐標(biāo),截取到的結(jié)果也是我們想要的

console.log('截取的結(jié)果為:',str.strSlice(0,5));

總結(jié)

到此這篇關(guān)于JS字符串截取出現(xiàn)的bug以及解決方式的文章就介紹到這了,更多相關(guān)JS字符串截取bug內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • javascript實(shí)現(xiàn)簡(jiǎn)約的頁(yè)面右下角點(diǎn)擊彈出窗口示例【測(cè)試可用】

    javascript實(shí)現(xiàn)簡(jiǎn)約的頁(yè)面右下角點(diǎn)擊彈出窗口示例【測(cè)試可用】

    這篇文章主要介紹了javascript實(shí)現(xiàn)的頁(yè)面右下角點(diǎn)擊彈出窗口功能,結(jié)合實(shí)例形式詳細(xì)分析了javascript頁(yè)面右下角點(diǎn)擊彈出窗口功能的相關(guān)步驟、原理與注意事項(xiàng),需要的朋友可以參考下
    2023-07-07
  • BootStrap實(shí)現(xiàn)手機(jī)端輪播圖左右滑動(dòng)事件

    BootStrap實(shí)現(xiàn)手機(jī)端輪播圖左右滑動(dòng)事件

    用bootstrap做出的項(xiàng)目輪播圖在手機(jī)端不能滑動(dòng),為此找了好多插件、框架。但是都不能和bootstrap良好的結(jié)合。經(jīng)過(guò)一番折騰終于找到了解決方法,下面小編通過(guò)本文給大家簡(jiǎn)單介紹下
    2016-10-10
  • 為什么JavaScript中0.1 + 0.2 != 0.3

    為什么JavaScript中0.1 + 0.2 != 0.3

    這篇文章主要給大家介紹了關(guān)于為什么JavaScript中0.1 + 0.2 != 0.3的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • electron 引入node服務(wù)的操作方法

    electron 引入node服務(wù)的操作方法

    這篇文章主要介紹了electron 引入node服務(wù)的操作方法,引入node服務(wù)很簡(jiǎn)單,直接在electron的主體中引入就可以了,對(duì)electron 引入node服務(wù)感興趣的朋友一起看看吧
    2024-03-03
  • JS如何設(shè)置元素樣式的方法示例

    JS如何設(shè)置元素樣式的方法示例

    本篇文章主要介紹了JS如何設(shè)置元素樣式的方法示例,主要介紹了三種方法,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • JS實(shí)現(xiàn)滑動(dòng)導(dǎo)航效果

    JS實(shí)現(xiàn)滑動(dòng)導(dǎo)航效果

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)滑動(dòng)導(dǎo)航效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • js HTML5 Ajax實(shí)現(xiàn)文件上傳進(jìn)度條功能

    js HTML5 Ajax實(shí)現(xiàn)文件上傳進(jìn)度條功能

    這篇文章主要介紹了javascript實(shí)現(xiàn)文件上傳進(jìn)度條功能的相關(guān)資料啊,感興趣的朋友可以參考一下
    2016-02-02
  • JavaScript驗(yàn)證一個(gè)url的方法總結(jié)

    JavaScript驗(yàn)證一個(gè)url的方法總結(jié)

    最近遇到幾次需要校驗(yàn)URL的,使用這篇文章小編就為大家整理了一下幾個(gè)JavaScript校驗(yàn)URL的方法,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以了解一下
    2023-12-12
  • JS小游戲之象棋暗棋源碼詳解

    JS小游戲之象棋暗棋源碼詳解

    這篇文章主要介紹了JS小游戲之象棋暗棋源碼詳解,對(duì)游戲源碼進(jìn)行了較為詳細(xì)的分析,并附帶完整實(shí)例代碼供大家學(xué)習(xí)參考,需要的朋友可以參考下
    2014-09-09
  • layui的面包屑或者表單不顯示的解決方法

    layui的面包屑或者表單不顯示的解決方法

    今天小編就為大家分享一篇layui的面包屑或者表單不顯示的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09

最新評(píng)論