js截取字符串substring、substr、slice出現(xiàn)的問題

背景問題

在處理用戶姓名的時候,我們希望截取最后一個字,有生僻字的時候,使用常規(guī)的截取會出現(xiàn)的問題,例如:趙??等,"趙??".length !=2,是等于3的。這樣就會有問題,

'吉'.length
// 1
'??'.length
// 2
'?'.length
// 1
'??'.length
// 2
text(str, start, end){
     //slice(),substring(),substr()截取字符串
     return src.slice(start,end)
},
//假設(shè)我們要截取字符串第一個字
let str = "??祥"
text(str, 0,1)
//結(jié)果是 ?

這里我們可以看到,有些生僻字他的長度是2,就會導(dǎo)致截取不出來,亂碼。具體原因可以看看UTF-16 的編碼邏輯。

解決方法

方法一

將字符串變成數(shù)組,然后再對字符串進行操作。這用Array.from

//假設(shè)我們要截取字符串最后一個字
text1(str) {
      let array = Array.from(str)
     return array.splice(array.length-1, 1).join('')
},
let str = "趙??"
text1(str)
//結(jié)果是 ??

方法二

在String定義一個新的函數(shù)處理,使用ES6的新特性String.fromCodePoint()和String.codePointAt(),將文本轉(zhuǎn)換成Unicode十六進制,判斷是否大于0xffff。

解釋圖.png
       text2(str, pStart, pEnd) {
            String.prototype.sliceByPoint = function (pStart, pEnd) {//給String添加新的函數(shù),分割字符串
                let result = '';//截取結(jié)果
                let pIndex = 0;//碼點的指針
                let cIndex = 0;//碼元的指針
                while (1) {
                    if (pIndex >= pEnd || cIndex >= this.length) {//碼點超過需要截取的點,碼元指向超過字符串長度,跳出循環(huán)
                        break;
                    }
                    const point = this.codePointAt(cIndex); //返回 一個 Unicode 編碼點值的非負整數(shù)
                    if (pIndex >= pStart) {
                        result += String.fromCodePoint(point) //String.fromCodePoint(point)返回使用指定的代碼點序列創(chuàng)建的字符串,(一串 Unicode 編碼位置,即“代碼點”)。
                    }
                    pIndex++
                    cIndex += point > 0xffff ? 2 : 1;
                }
                return result;
            }
            return str.sliceByPoint(pStart,pEnd)
        },
        //通過字符串獲取字符索引,與indexOf功能類似
        getIndex(str, char) {
            String.prototype.indexByStr = function (char) {//給String添加新的函數(shù)(‘indexByStr ’可以換一個名),通過字符串獲取字符索引,與indexOf功能類似
                let result = '';//截取結(jié)果
                let pIndex = 0;//碼點的指針
                let cIndex = 0;//碼元的指針
                while (1) {
                    if (cIndex >= this.length) {//碼元指向超過字符串長度,跳出循環(huán)
                        break;
                    }
                    const point = this.codePointAt(cIndex); //返回 一個 Unicode 編碼點值的非負整數(shù)
                    console.log()
                    if (String.fromCodePoint(point) == char) {
                        result = pIndex
                        break;
                    }
                    pIndex++
                    cIndex += point > 0xffff ? 2 : 1;
                }
                return result;
            }
            return str.indexByStr(char)
        },
      //獲取字符串長度,與length功能相似
        getLength(str) {
            String.prototype.LengthByStr = function () {//給String添加新的函數(shù)(‘LengthByStr ’可以隨便?。@取字符串長度,與length功能相似
                let pIndex = 0;//碼點的指針
                let cIndex = 0;//碼元的指針
                while (1) {
                    if (cIndex >= this.length) {//碼點超過需要截取的點,碼元指向超過字符串長度,跳出循環(huán)
                        break;
                    }
                    const point = this.codePointAt(cIndex); //返回 一個 Unicode 編碼點值的非負整數(shù)
                    pIndex++
                    cIndex += point > 0xffff ? 2 : 1;
                }
                return pIndex;
            }
            return str.LengthByStr(str)
        }
      //假設(shè)我們要截取字符串最后一個字
    let str = "趙??"
    text2(str,  this.getLength(str)-1, this.getLength(str))
    //返回結(jié)果是 ??

總結(jié)

        let str = "";
        for (let i = 0; i < 10000000; i++) {
            str = str + '你'
        }
        str = str+ "????????"
        console.time('global')
        console.log("text1==",this.text1(str))
        console.timeEnd('global')
        console.time('global')
        console.log("text2==",this.text2(str, this.getLength(str)-1, this.getLength(str)))
        console.timeEnd('global')

    //控制臺打印
    text1== ??
    global: 3342.0859375 ms
    text2== ??
    global: 111.992919921875 ms

1、通用的字符串操作,能解決大多數(shù)問題。
2、方法一靈活性高,代碼少,大多數(shù)情況下這種都能解決。
3、如果字符串長度很長很長,字符串轉(zhuǎn)數(shù)組就會很慢很慢,方法二性能高,運行速度快。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容