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

相关