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 編碼點值的非負(fù)整數(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 編碼點值的非負(fù)整數(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 編碼點值的非負(fù)整數(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)系作者
  • 序言:七十年代末物延,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仅父,更是在濱河造成了極大的恐慌,老刑警劉巖浑吟,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笙纤,死亡現(xiàn)場離奇詭異,居然都是意外死亡组力,警方通過查閱死者的電腦和手機省容,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來燎字,“玉大人腥椒,你說我怎么就攤上這事『蜓埽” “怎么了笼蛛?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蛉鹿。 經(jīng)常有香客問我滨砍,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任惋戏,我火速辦了婚禮领追,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘响逢。我一直安慰自己绒窑,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布舔亭。 她就那樣靜靜地躺著些膨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪分歇。 梳的紋絲不亂的頭發(fā)上傀蓉,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音职抡,去河邊找鬼葬燎。 笑死,一個胖子當(dāng)著我的面吹牛缚甩,可吹牛的內(nèi)容都是我干的谱净。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼擅威,長吁一口氣:“原來是場噩夢啊……” “哼壕探!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起郊丛,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤李请,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后厉熟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體导盅,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年揍瑟,在試婚紗的時候發(fā)現(xiàn)自己被綠了白翻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡绢片,死狀恐怖滤馍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情底循,我是刑警寧澤巢株,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站此叠,受9級特大地震影響纯续,放射性物質(zhì)發(fā)生泄漏随珠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一猬错、第九天 我趴在偏房一處隱蔽的房頂上張望窗看。 院中可真熱鬧,春花似錦倦炒、人聲如沸显沈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拉讯。三九已至,卻和暖如春鳖藕,著一層夾襖步出監(jiān)牢的瞬間魔慷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工著恩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留院尔,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓喉誊,卻偏偏與公主長得像邀摆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伍茄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容