温馨提示:若有更好的算法欢迎评论交流,不想看分析的直接Crtl+C,然后出门左转,不客气!
主要原理:
假设有这样的字符串originalStr = '中E文N中'
A. 将字符串分割
中 E 文 N 中 B. 按照中文字符算法长度=1,其它字符算法长度=0.5的规则对算法长度进行自加标注,如下表:
算法长度 1 1.5 2.5 3 4 字符 中(+1) E(+0.5) 文(+1) N(+0.5) 中(+1) 字符在数组中的index 0 1 2 3 4 C. 根据传入需要截取的字符长度值: 例如 limit = 3,去所有的算法长度值里面匹配,如下:
limit 3 3 3 3 3 算法长度 1 1.5 2.5 3 4 X X X 匹配成功 X
若直接匹配不到,则按照limit的 +0.5 和 -0.5 来匹配,(1.5,2,2.5) limit(现在假设=2) 1.5 1.5 1.5 1.5 1.5 算法长度(没有=2的)
优先取左边的(1.5),没有再取右边的(2.5)
1 1.5 2.5 3 4 X 匹配成功 X X X D. 获取"算法长度"=3 的那一列的 "字符在数组中的index"=3,这样拿到了要截取的字符串的最后一个字符的索引
算法长度 1 1.5 2.5 3(匹配成功的算法长度) 4 字符在数组中的index 0 1 2 3(对应的字符的索引 index) 4 E. 得到结果: resultStr = originalStr.slice(0, index+1)
代码用的JavaScript,其它的算法逻辑都一样,语法不同而已,各位看官自己照着写吧。
export function sliceCnEq2(s, limit) {
if (s) {
if (limit <= 0) {
return '';
} else {
let l = 0;
let indexMap = [];
for (let i = 0; i < s.length; i++) {
if (isCn(s[i])) {
l++;
} else {
l = l + 0.5;
}
indexMap.push({
lIndex: l,
sIndex: i
})
}
if (l <= limit) {
return s;
} else {
let sliceEnd = -2;
let range = [limit, (limit - 0.5), (limit + 0.5)];
for (let j = 0; j < range.length; j++) {
if (sliceEnd <= 0) {
for (let i = 0; i < indexMap.length; i++) {
if (range[j] === indexMap[i].lIndex) {
sliceEnd = indexMap[i].sIndex;
break;
}
}
}
}
return s.slice(0, sliceEnd + 1) + '...';
}
}
} else {
return '';
}
}
//附
export function isCn(s) {
return !!s.match('[|\u4E00-\u9FFF|]');
}