【关于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,二进制是100111000100101,需要16位,能表示16位的utf-8,就需要3个字节了。
【lua中获取字符串长度】
# lua中的字符串使用的是utf-8编码,如果直接使用string.len获取到的是字节(byte)长度,而不是字符(char)长度
1 function string.utf8CharSize(c) 2 if not c then return 0 end 3 if c > 240 then return 4 end 4 if c > 225 then return 3 end 5 if c > 192 then return 2 end 6 return 1 7 end 8 9 function string.utf8StringLen(str) 10 if nil == str or "" == str then return 0 end 11 assert("string" == type(str), "not string") 12 13 local len = 0 14 local i = 1 15 while i <= #str do 16 local b = string.byte(str, i) 17 i = i + string.utf8CharSize(b) 18 len = len + 1 19 end 20 return len 21 end 22 23 function string.utf8StringSub(str, index, count) 24 if nil == index then index = 1 end 25 if nil == count then count = string.utf8StringLen(str) end 26 27 local byteCount = #str 28 local i = 1 29 --跳过起始的n个 30 while index > 1 and i <= byteCount do 31 local b = string.byte(str, i) 32 i = i + string.utf8CharSize(b) 33 index = index - 1 34 end 35 36 local j = i 37 --子串结束位置 38 while count > 0 and j <= byteCount do 39 local b = string.byte(str, j) 40 j = j + string.utf8CharSize(b) 41 count = count - 1 42 end 43 44 return str:sub(i, j-1) 45 end 46 47 function string.utf8CharArray(str, index, count, dstTb, dstIndex) 48 if nil == index then index = 1 end 49 if nil == count then count = string.utf8StringLen(str) end 50 if nil == dstTb then dstTb = {} end 51 52 local byteCount = #str 53 local i = 1 54 --跳过起始的n个 55 while index > 1 and i <= byteCount do 56 local b = string.byte(str, i) 57 i = i + string.utf8CharSize(b) 58 index = index - 1 59 end 60 61 local j = i 62 local leftCount = count 63 --子串结束位置 64 if nil == dstIndex then 65 while leftCount > 0 and j <= byteCount do 66 local b = string.byte(str, j) 67 local size = string.utf8CharSize(b) 68 local utf8Char = str:sub(j, j+size-1) 69 table.insert(dstTb, utf8Char) 70 j = j + size 71 leftCount = leftCount - 1 72 end 73 else 74 while leftCount > 0 and j <= byteCount do 75 local b = string.byte(str, j) 76 local size = string.utf8CharSize(b) 77 local utf8Char = str:sub(j, j+size-1) 78 dstTb[dstIndex] = utf8Char 79 j = j + size 80 leftCount = leftCount - 1 81 dstIndex = dstIndex + 1 82 end 83 end 84 85 return dstTb, count 86 end
测试代码:
1 local function Test1() 2 assert(6 == string.utf8StringLen("123abc")) 3 assert(2 == string.utf8StringLen("中文")) 4 assert(4 == string.utf8StringLen("中文1a")) 5 assert(5 == string.utf8StringLen(".,;<>")) 6 assert(5 == string.utf8StringLen("。,;《》")) 7 assert(10 == string.utf8StringLen(".,;<>。,;《》")) 8 9 assert("文1" == string.utf8StringSub("中文1a", 2, 2)) 10 assert("文啊" == string.utf8StringSub("中文啊呀", 2, 2)) 11 12 local tb = string.utf8CharArray("中文啊呀", 2, 2) 13 assert("文" == tb[1]) 14 assert("啊" == tb[2]) 15 end 16 17 Test1()
【参考】
Lua 的 # 获取长度 - 简书 (jianshu.com)