lua字符串长度
【关于unicode和utf-8】
# unicode字符集,包含了全世界的字符,然而它只是规定了字符的二进制编码,并没有规定二级制编码是如何存储的。utf-8就是unicode的一个实现方式,就是怎么存储和读取这个unicode二进制编码。
就像一张jpg图片,我们可以选择直接存放在硬盘上,也可以压缩成rar后保存,也可以压缩成7z后保存,UTF-8就类似这边的rar和7z。
【utf-8】
# utf-8是一个可变长的编码方式,有的是用1个字节存,有的采用2个,有的3个,最多可采用6个字节,既然是可变的,就要求字节中有个位数用来表示标记的,,有了标记就知道怎么读取字节了。
# 1个字节表示的编码,最高位是0,像这样0xxxxxxx。后面7位x来表示unicode编码,当然7位表示的编码有限。
# n个字节的编码,需要第一个byte的前n bit用1表示,n+1位用0,其余的字节前两位是10,如2个字节的 110xxxxx 10xxxxxx,3个字节的1110xxxx 10xxxxxx 10xxxxxx等的,除了符号位,剩下的x就用来表示unicode编码了,例如 "严"的unicode是4E25,二进制是01001110, 00100101,存储成utf-8的话需要3个字节(2个字节110xxxxx 10xxxxxx这种存不下)
【lua中获取字符串长度】
# lua中的字符串使用的是utf-8编码,如果直接使用string.len获取到的是字节(byte)长度,而不是字符(char)长度
---@param b byte 根据第1个字节判断utf-8字符存放字节大小 function string.utf8CharSize(b) if not b then return 0 end if b >= 0xfc then return 6 end -- 1111110x if b >= 0xf8 then return 5 end -- 111110xx if b >= 0xf0 then return 4 end -- 11110xxx if b >= 0xe0 then return 3 end -- 1110xxxx if b >= 0xc0 then return 2 end -- 110xxxxx return 1 -- 0xxxxxxx end ---@param str string ---@return number function string.utf8StringLen(str) if nil == str or "" == str then return 0 end assert("string" == type(str), "not string") local len = 0 local i = 1 while i <= #str do local b = string.byte(str, i) i = i + string.utf8CharSize(b) len = len + 1 end return len end ---@param str string ---@param index number|null 开始索引, 该索引的字符包含在内 ---@param count number|null 裁剪数量 ---@return string function string.utf8StringSub(str, index, count) index = index or 1 count = count or string.utf8StringLen(str) local byteCount = #str local i = 1 --跳过起始的n个 while index > 1 and i <= byteCount do local b = string.byte(str, i) i = i + string.utf8CharSize(b) index = index - 1 end local j = i --子串结束位置 while count > 0 and j <= byteCount do local b = string.byte(str, j) j = j + string.utf8CharSize(b) count = count - 1 end return str:sub(i, j-1) end ---@param str string ---@param index number 开始索引 ---@param count number 数量 ---@param dstTb any[] ---@param dstIndex number ---@return any[], number function string.utf8CharArray(str, index, count, dstTb, dstIndex) if nil == index then index = 1 end if nil == count then count = string.utf8StringLen(str) end if nil == dstTb then dstTb = {} end local byteCount = #str local i = 1 --跳过起始的n个 while index > 1 and i <= byteCount do local b = string.byte(str, i) i = i + string.utf8CharSize(b) index = index - 1 end local j = i local leftCount = count --子串结束位置 if nil == dstIndex then while leftCount > 0 and j <= byteCount do local b = string.byte(str, j) local size = string.utf8CharSize(b) local utf8Char = str:sub(j, j+size-1) table.insert(dstTb, utf8Char) j = j + size leftCount = leftCount - 1 end else while leftCount > 0 and j <= byteCount do local b = string.byte(str, j) local size = string.utf8CharSize(b) local utf8Char = str:sub(j, j+size-1) dstTb[dstIndex] = utf8Char j = j + size leftCount = leftCount - 1 dstIndex = dstIndex + 1 end end return dstTb, count end
测试代码:
local function Test1() assert(6 == string.utf8StringLen("123abc")) assert(2 == string.utf8StringLen("中文")) assert(4 == string.utf8StringLen("中文1a")) assert(5 == string.utf8StringLen(".,;<>")) assert(5 == string.utf8StringLen("。,;《》")) assert(10 == string.utf8StringLen(".,;<>。,;《》")) assert("文1" == string.utf8StringSub("中文1a", 2, 2)) assert("文啊" == string.utf8StringSub("中文啊呀", 2, 2)) local tb = string.utf8CharArray("中文啊呀", 2, 2) assert("文" == tb[1]) assert("啊" == tb[2]) end
【参考】
Lua 的 # 获取长度 - 简书 (jianshu.com)

浙公网安备 33010602011771号