计算和截取指定字符串的UTF-8字节数
2019-08-28 本文已影响0人
躺在家里干活
由于特殊需求,需要限制输入框内容的长度,但是该长度并不是普通的字数长度而是UTF-8的字节数
UTF-8编码下 字节数
占2个字节的:〇
占3个字节的:基本等同于GBK,含21000多个汉字
占4个字节的:中日韩超大字符集里面的汉字,有5万多个
一个utf8数字占1个字节
一个utf8英文字母占1个字节
Unicode码
1个字节:Unicode码为0 - 127
2个字节:Unicode码为128 - 2047
3个字节:Unicode码为2048 - 0xFFFF
4个字节:Unicode码为65536 - 0x1FFFFF
5个字节:Unicode码为0x200000 - 0x3FFFFFF
6个字节:Unicode码为0x4000000 - 0x7FFFFFFF
计算指定字符串的字节数
function computeByteSize(str){
for (var i=0,byte=0; i < str.length; i++) {
var charCode = str.charCodeAt(i);
if (0 <= charCode && charCode <= 0x7f) {
byte += 1;
} else if (128 <= charCode && charCode <= 0x7ff) {
byte += 2;
} else if (2048 <= charCode && charCode <= 0xffff) {
byte += 3;
} else if (65536 < charCode && charCode <= 0x1FFFFF) {
byte += 4;
} else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
byte += 5;
} else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
byte += 6;
}
}
return byte
}
//es6写法
function computeByteSize(str) {
let byte=0;
for (const chr of str) {
//ES6提供了codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点
//能正确地识别“?”,返回了它的十进制码点 134071(即十六进制的20BB7)
let charCode = chr.codePointAt(0)
if(0 <= charCode && charCode <= 0x7f) {
byte += 1;
} else if (128 <= charCode && charCode <= 0x7ff) {
byte += 2;
} else if (2048 <= charCode && charCode <= 0xffff) {
byte += 3;
} else if (65536 < charCode && charCode <= 0x1FFFFF) {
byte += 4;
} else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
byte += 5;
} else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
byte += 6;
}
}
return byte
}
截取指定字节数的字符串
function cutStr(str,L){
for (var i=0,byte=0,result=''; i < str.length; i++) {
var chr = str.charAt(i);
var charCode = str.charCodeAt(i);
if (0 <= charCode && charCode <= 0x7f) {
byte += 1;
} else if (128 <= charCode && charCode <= 0x7ff) {
byte += 2;
} else if (2048 <= charCode && charCode <= 0xffff) {
byte += 3;
} else if (65536 < charCode && code <= 0x1FFFFF) {
byte += 4;
} else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
byte += 5;
} else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
byte += 6;
}
// 当加上当前字符以后,如果总字节长度小于等于L,则将当前字符真实的+在result后
if(byte<=L){
result += chr;
}else{
return result;
}
}
}
//es6 写法
function cutStr(str, L) {
let byte=0;
let result='';
for(let chr of str){
let charCode = chr.codePointAt(0)
if (0 <= charCode && charCode <= 0x7f) {
byte += 1;
} else if (128 <= charCode && charCode <= 0x7ff) {
byte += 2;
} else if (2048 <= charCode && charCode <= 0xffff) {
byte += 3;
} else if (65536 < charCode && charCode <= 0x1FFFFF) {
byte += 4;
} else if (0x200000 < charCode && charCode <= 0x3FFFFFF) {
byte += 5;
} else if (0x4000000 < charCode && charCode <= 0x7FFFFFFF) {
byte += 6;
}
// 当加上当前字符以后,如果总字节长度小于等于L,则将当前字符真实的+在result后
if (byte <= L) {
result += chr;
} else {
return result;
}
}
}
应用demo
<textarea></textarea>
<div class="number"></div>
<script type="text/javascript" src="js/jquery-3.2.1.js"></script>
<script type="text/javascript">
$(function(){
//及时监听文本框内容的变化
$("textarea").bind('input propertychange',function(){
var str = $(this).val()
var len = computeByteSize(str)
if(len>256){
$(this).val(cutStr(str,256))
}else{
$('.number').html(len)
}
});
})
</script>
但是目前截取字符串存在一些bug,如果直接复制一段中文内容到文本框,复制的内容超过限制的字节数,则会造成number的内容出错。而且如果输入的为中文,因为一个中文为3个字节数,一个拼音为一个字节数。所以也会出错。有可能造成最后的中文无法显示
注:汉字“?”(注意,这个字不是“吉祥”的“吉”)的码点是0x20BB7,UTF-16 编码为0xD842 0xDFB7(十进制为55362、57271),需要4个字节储存。对于这种4个字节的字符,JavaScript 不能正确处理,字符串长度会误判为2,而且charAt方法无法读取整个字符,charCodeAt方法只能分别返回前两个字节和后两个字节的值。因此ES6 提供了codePointAt方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。codePointAt 方法在第一个字符上,正确地识别了“?”,返回了它的十进制码点 134071(即十六进制的20BB7)