前置知识

字节

字节(Byte)是计算机信息技术用于计量存储容量的一种计量单位,也表示一些计算机编程语言中的数据类型和语言字符。

  • 一个字节(byte)8位(bit),十进制表示0~255。
  • 两个字节16位,可表示十进制0~65535。

Unicode字符集

Unicode 做了一件事,就是给世界上所有字符都分配了一个唯一的数字编号,这个编号范围从0x000000~0x10FFFF,包括110多万。但大部分常用字符都在0x0000~0xFFFF之间,即65536个数字之内。每个字符都有一个Unicode编号,这个编号一般写成十六进制,在前面加U+。编号怎么对应到二进制表示呢?有多种方案,主要有UTF-32、UTF-16和UTF-8。

JavaScript 使用 Unicode 字符集,采用 UTF-16 编码方案(整合UCS-2编码。一开始JavaScript采用的是UCS-2,那时候Unicode的UTF-16标准还没发布)。UTF-16兼容ASCII,即前128个Unicode代码点是ASCII字符编码的直接匹配。


各字符集中汉字所占字节

  • ASCii字符集:只有英文、数字、符号等,占1个字节。
  • GBK字符集:汉字占2个字节,英文、数字占1个字节。
  • UTF-32字符集:汉字占4个字节,英文、数字占2个字节。
  • UTF-8字符集:汉字占3个字节,英文、数字占1个字节。

数据库中字段长度

  • Oracle

    • Oracle中varchar2类型的字段长度单位默认是按照byte(字节)来定义,比如常见写法varchar2(10)代表只接收最大10字节长度。
    • 其实我们在Oracle中也可以用字符为单位来定义varchar2字段的长度,这个时候需要注意在建表时写成VARCHAR2(10 char)。
  • MySql

    • 5.X 以上的版本的定义中表示的字符长度,如上varchar(20)你既可以添加20个英文字符,也可以添加二十个中文字符。
    • 4.X 的版本表示的是字节长度,会根据字符集转变内容字节长度存储。
  • 使用oracle数据库或mysql4.x数据库,就需要注意所提交字符(串)的字节长度。


方法charCodeAt

charCodeAt()方法返回 0 到 65535 之间的整数,表示给定索引处的 UTF-16 代码单元(小知识:2的16次方等于65536)。

有些网友说返回的是十六进制的整数,我们可以进行如下测试验证一下:

var str = "编码"
console.log('测试数据 = '+ str.charAt(0))
console.log('------------------- ')
console.log('情况一:charCodeAt返回的是16进制的unicode编码')
//十六进制
var code16 = str.charCodeAt(0)
console.log('十六进制编码 = '+ code16)
// 使用eval(),将十六进制的unicode编码转换为字符
var res = eval("'\\u" + code16 + "'")
console.log('恢复成字符 = '+ res+ ";测试"+(res == str.charAt(0)?"通过✅":"不通过❌"))
console.log('------------------- ')

console.log('情况一:charCodeAt返回的是10进制的unicode编码')
//十进制
var code10 = str.charCodeAt(0)
console.log('十进制编码 = '+ code10)
console.log('十六进制编码 = '+ code10.toString(16))
// 使用eval(),将十六进制的unicode编码转换为字符
var res2 = eval("'\\u" + code10.toString(16) + "'")
console.log('恢复成字符 = '+ res2+ ";测试"+(res2 == str.charAt(0)?"通过✅":"不通过❌"))
console.log('------------------- ')


测试数据 =------------------- 
情况一:charCodeAt返回的是16进制的unicode编码
十六进制编码 = 32534
恢复成字符 =4;测试不通过❌
------------------- 
情况一:charCodeAt返回的是10进制的unicode编码
十进制编码 = 32534
十六进制编码 = 7f16
恢复成字符 = 编;测试通过✅
------------------- 

测试结果表明,返回的是十进制的整数。


字符串(字节)长度计算

需求:前端向后端提交数据,数据库字段限制了长度,一般单位是字节,中英文字符所占字节数是不一样的。所以对于中英文混合的数据不能直接使用字符串的length属性来获取长度(字符个数)。


思路

  • 要明确后端数据库所采用的字符集,再计算数据提交到数据库后实际所占的字节长度(是否符合数据库字段所限制长度)。
  • 使用方法charCodeAt(),获取字符的unicode编码(0 到 65535 之间的整数)。
  • 常见英文字母、英文标点符号(半角符号),unicode编码小于128(0~127。1字节可表示0~255),即ASCII编码。
  • 判断方法charCodeAt()返回的整数是否大于255(0开始),若大于则认为是汉字字符。也有网友通过判断unicode编码是否大于127作为分界。
/**
 * 获取字节长度。
 * ASCii字符集:只有英文、数字、符号等,占1个字节。
 * GBK字符集:汉字占2个字节,英文、数字占1个字节。
 * UTF-32字符集:汉字占4个字节,英文、数字占2个字节。
 * UTF-8字符集:汉字占3个字节,英文、数字占1个字节。
 */
function getByteLen(value, charset) {
	var charlen = 2; //默认 1个汉字占2字节
	if (!charset) {
		charset = 'gbk'; //默认为gbk(数据库中最常用的字符集是utf-8、gbk)
	}
	if ((charset + "").toLowerCase().indexOf('gb') == 0) { //GB2312、GBK、GB18030
		charlen = 2;
	}
	if ((charset + "").toLowerCase() == 'utf-8') {
		charlen = 3;
	}
	if ((charset + "").toLowerCase() == 'utf-32') {
		charlen = 4;
	}
	if (value == null || value.length < 1) return 0;
	var len = 0;
	for (var i = 0; i < value.length; i++) {
		if (value.charCodeAt(i) < 255) {
			len++;
		} else {
			len += charlen;

		}
	}
	return len;
}

示例:

console.log(getByteLen('ab我', 'utf-8')); //5
console.log(getByteLen('ab我', 'gbk')); //4
console.log(getByteLen('ab我')); //4

扩展

实现字符与unicode编码互转,见这篇博客


参考:CSDN脚本之家百度百科《Java编程的逻辑》-马俊昌

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐