在我们日常游戏开发中,经常会面临将玩家名字截断的需求。
假如玩家是在我们游戏中创建的名字,那么可以简单粗暴地禁止玩家使用手机表情输入即可。
但如果我们是第三方账号登录,且使用了第三方账号的用户昵称,那么这个就不好保证了。
因此,为了配合界面的显示,我们通常需要在特定界面上进行名字截断。
举一个例子,假如我的名字是 麒麟子?? 我们一眼看过去,是5个字。
但在计算机中可不是5个字,即使是全部用UTF8表示字符的javascript中,console.log('麒麟子?哈?'.length) 也是8.
也就是说表情符号占用了 4个字符。 如果我们按UTF8去截断,必然会导致乱码。
因此我们定义以下规则
1、ascii字符,算1个字符
2、汉字,算2个字符
3、手机系统表情,看2个字符 (因为它们虽然占了4个字符,但是从显示宽度上来看,依然是2个字符)。
下面的函数 strClamp 可助你一臂之力, 这是麒麟子从 幼麟棋牌最新5.0框架中抠出来的代码,希望能够帮助到大家
//str 需要截断的字符串
//maxChars 保留的汉字长度
//suffix 添加的后缀 (注意,如果后缀不为null或者'' ,则要占用一个汉字的位置,具体看下方的示例代码)
function strClamp(str, maxChars, suffix) {
var toCodePoint = function(unicodeSurrogates) {
var r = [], c = 0, p = 0, i = 0;
while (i < unicodeSurrogates.length) {
var pos = i;
c = unicodeSurrogates.charCodeAt(i++);//返回位置的字符的 Unicode 编码
if (c == 0xfe0f) {
continue;
}
if (p) {
var value = (0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00));
r.push({
v: value,
pos: pos,
}); //计算4字节的unicode
p = 0;
} else if (0xD800 <= c && c <= 0xDBFF) {
p = c; //如果unicode编码在oxD800-0xDBff之间,则需要与后一个字符放在一起
} else {
r.push({
v: c,
pos: pos
}); //如果是2字节,直接将码点转为对应的十六进制形式
}
}
return r;
}
suffix = suffix==null? '...' : suffix;
maxChars *= 2;
var codeArr = toCodePoint(str);
var numChar = 0;
var index = 0;
for (var i = 0; i < codeArr.length; ++i) {
var code = codeArr[i].v;
var add = 1;
if (code >= 128) {
add = 2;
}
//如果超过了限制,则按上一个为准
if (numChar + add > maxChars){
break;
}
index = i;
//累加
numChar += add;
}
if(codeArr.length - 1 == index){
return str;
}
var more = suffix? 1:0;
return str.substring(0, codeArr[index - more].pos + 1) + suffix;
}
//示例:
var str = '麒麟子?哈?;
strClamp(str,3,'...') // 得到 麒麟...
strClamp(str,3,'') // 得到 麒麟子