背景問題
在處理用戶姓名的時候票堵,我們希望截取最后一個字扼睬,有生僻字的時候,使用常規(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卿操。
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ù)組就會很慢很慢曹鸠,方法二性能高,運行速度快摩梧。