偶然的情况下,需要用Lua代码获取字符串的长度,结果发现结果和自己想象的不一样,一个汉字算两个英文字符的时代已经快过去了,一个中文字符打印出来的长度为3,引起了我的好奇,查找资料了解了具体原因
不同的编码格式占字节数是不同的,UTF-8编码下一个中文所占字节也是不确定的,通常是3个字符,可能是2个、4个字节;
出于效率考虑,于是又弄了一个UTF-16,不严谨地来说它等价于Unicode原生编码,它统一采用双字节表示一个字符
下面是Unicode和UTF-8转换的规则
1 Unicode 2 3 UTF-8 4 5 0000 - 007F 6 7 0xxxxxxx 8 9 0080 - 07FF
10
11 110xxxxx 10xxxxxx
12
13 0800 - FFFF
14
15 1110xxxx 10xxxxxx 10xxxxxx
例如"汉"字的Unicode编码是6C49
6C49在0800-FFFF之间,所以要用3字节模板:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 1100 0100 1001,将这个比特流按三字节模板的分段方法分为0110 110001 001001,依次代替模板中的x,得到:
1110-0110 10-110001 10-001001,即E6 B1 89,这就是其UTF8的编码
GBK、GB2312收编的汉字占2个字节,严格地用iso8859-1无法表示汉字,只能转为问号
下面是Lua获取字符串长度的方法:
方案一:
-- 获取字符串的长度(任何单个字符长度都为1)
function getStringLength(inputstr)if not inputstr or type(inputstr) ~= "string" or #inputstr <= 0 thenreturn nilendlocal length = 0 -- 字符的个数local i = 1while true dolocal curByte = string.byte(inputstr, i)local byteCount = 1if curByte > 239 thenbyteCount = 4 -- 4字节字符elseif curByte > 223 thenbyteCount = 3 -- 汉字elseif curByte > 128 thenbyteCount = 2 -- 双字节字符elsebyteCount = 1 -- 单字节字符end-- local char = string.sub(inputstr, i, i + byteCount - 1)-- print(char) -- 打印单个字符i = i + byteCountlength = length + 1if i > #inputstr thenbreakendendreturn length
endlocal str = "I think,故我在!"
local len = getStringLength(str)
print(len) -- 12
方案二:
-- 计算 UTF8 字符串的长度,每一个中文算一个字符
function utf8len(input)local len = string.len(input)local left = lenlocal cnt = 0local arr = {0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}while left ~= 0 dolocal tmp = string.byte(input, left)local i = #arrwhile arr[i] doif tmp >= arr[i] thenleft = left - ibreakendi = i - 1endcnt = cnt + 1endreturn cnt
endlocal str = "I think,故我在!"
local len = utf8len(str)
print(len) -- 12
一个汉字占几个字节,详解与原理:
https://www.cnblogs.com/lslk89/p/6898526.html
https://blog.csdn.net/wowotuo/article/details/60333350
Lua中获取字符串长度:https://blog.csdn.net/fightsyj/article/details/83589997