Lua中获取字符串长度
首先是关于字符长度的一些结束(可以不看)
在 Lua 中,获取字符串长度我们一般使用 #str(不建议使用 string.len(str) )!
local str = "abc" local len = #str print(len) -- 3 str = "你们好" len = #str print(len) -- 9
疑惑:
这里就出现了一个问题:为啥字符串 abc 的长度为 3,而字符串 你们好 的长度却是 9 呢?难道是哪里出问题了?当然不是!
其实这是字符编码导致的,在使用 UTF-8 字符编码的情况下,一个中文字符一般占 3 个字节,所以 3 个中文字符自然就是 9 个字节咯!
那么问题来了,现在我需要不管是中文字符还是其他字符,长度都为 1 该咋整呢?
查找资料了解了具体原因:
不同的编码格式占字节数是不同的,UTF-8编码下一个中文所占字节也是不确定的,通常是3个字符,可能是2个、4个字节;
出于效率考虑,于是又弄了一个UTF-16,不严谨地来说它等价于Unicode原生编码,它统一采用双字节表示一个字符
下面是Unicode和UTF-8转换的规则
Unicode
||
UTF-8
0000 - 007F
||
0xxxxxxx
0080 - 07FF
||
110xxxxx 10xxxxxx
0800 - FFFF
||
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 相关文章2
方案二
-- 计算 UTF8 字符串的长度,每一个中文算一个字符
function utf8len(input)
local len = string.len(input) --这里获取到的长度为字节数,如示例长度为:21,而我们肉眼看到的长度应该是15(包含空格)
local left = len --将字节长度赋值给将要使用的变量,作为判断退出while循环的字节长度
local cnt = 0 --将要返回的字符长度
local arr = {0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc} --用来判断是否满足字节长度的列表
while left ~= 0 do --遍历每一个字符
--获取字节的ASCII值,这里的 “-” 代表反向对应的索引,-left:input反着第left
--假设字符串字符input长度是:21,left的值是:21,那string.byte(input, -left)就是第一个字节的ASCII值
local tmp = string.byte(input, -left) --看上面两行
local i = #arr --获取判断列表的长度,同时作为字节长度
while arr[i] do --循环判定列表
if tmp >= arr[i] then --判定当前 “字符” 的 头“字节” ACSII值符合的范围
left = left - i --字符串字节长度 -i,也就是 减去字节长度
break --结束判断
end
i = i - 1 --每次判断失败都说明不符合当前字节长度
end
cnt = cnt + 1 --“字符” 长度+1
end
return cnt --返回 “字符” 长度
end
local str = "I think,故我在.bmp"
local len = utf8len(str) --获取字符串字符长度
print(string.format("Number of characters: %s\nNumber of bytes: %s", len, str:len()))
注:方案二与方案一原理差不多,都是根据每个字符的头 “字节” 来判断字节长度,不同的是方案二是先遍历一个判断列表,根据符合 / 不符合条件来判断字节长度,如果一开始就符合了范围,那么字节长度就是判断列表的长度 “5”了,不过显然我们的示例字符串最大的字节长度也就 “3”
相关参考文章:文章1 文章2