一般在工作中会遇到中文字符的判断、截断、打码等需求,之前一直没有总结,虽然网上资料也多,今天在这里简单的总结一下。
UTF-8 是 Unicode 的实现方式之一,其对应关系(编码规则)如下表所示:

Unicode 可以容纳100多万个符号
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
2 .UTF-8的中文字符编码如何生成
例如 将中,龙两个字从Unicode转换为UTF-8:
0x4E2D(0100 1110 0010 1101),根据上表,处于第三行范围内,UTF-8编码需要三个字节,格式为 1110xxxx 10xxxxxx 10xxxxxx。中的Unicode 二进制填充进这个格式,得到 11100100 10111000 10101101,转换为十进制是 228,184,173print(string.char(228,184,173)) => 中0x9F99 (1001 1111 1001 1001) ,同样处于第三行范围内。11101001 10111110 10011001(233,190,153)print(string.char(233,190,153)) => 龙
通常来说,汉字范围从0x4E00到0x9FA5,转换为UTF-8编码为11100100 10111000 10000000(228, 184, 128) 到 11101001 10111110 10100101(233, 190, 165)
因此,中文UTF-8编码用3个字节表示,要遵守格式:1110xxxx 10xxxxxx 10xxxxxx
即第一个字节的取值区间为 [11100000, 11110000) = [0xe0, 0xf0) = [224, 240) 左开右闭
后两个字节的取值区间为[10000000, 10111111] = [0x80,0xbf] = [128, 191] 开区间
4.如何取得字节ASCII码 - string.byte()
5.字符是由几个字节组成
读取第一个字节,在以下区间的代表不同的字节数:
0, 0xc0) 表示这个字符仅由1个字节构成0xc0, 0xe0) 表示这个字符由2个字节构成0xe0, 0xf0) 表示这个字符由3个字节构成0xf0, 0xff) 表示这个字符由4个字节构成
- -- 判断utf8字符byte长度
- -- [0, 0xc0) 表示这个字符仅由1个字节构成 [0,192)
- -- [0xc0, 0xe0) 表示这个字符由2个字节构成 [192,224)
- -- [0xe0, 0xf0) 表示这个字符由3个字节构成 [224,240)
- -- [0xf0, 0xff) 表示这个字符由4个字节构成 [240,255)
- function Utils.getChrSize(char)
- if not char then
- return 0
- elseif char >= 240 then
- return 4
- elseif char >= 224 then
- return 3
- elseif char >= 192 then
- return 2
- elseif char >= 0 then
- return 1
- end
- end
6.附加几个常用的函数
我的需求:
- -- 把字符串转换成第一个显示后面是**号 如:中国人 -> 中**
- function Utils.changeTextExpress(str)
- if not str then return str end
- local tempStr = ""
- local len = string.utf8len(str)
-
- local first = string.byte(str, 1)
- local firstLen = sgs.utils.getChrSize(first)
- tempStr = string.sub(str, 1,firstLen)
-
- for i=1,len-1 do
- tempStr = tempStr .. "*"
- end
-
- return tempStr
- end
再附加几个其他的方法:
- -- 计算 UTF8 字符串的长度,每一个中文算一个字符
- -- @function [parent=#string] utf8len
- -- @param string input 输入字符串
- -- @return integer#integer 长度
-
- --[[--
- 计算 UTF8 字符串的长度,每一个中文算一个字符
- ~~~ lua
- local input = "你好World"
- print(string.utf8len(input))
- -- 输出 7
- ~~~
- ]]
-
- -- end --
-
- function string.utf8len(input)
- local len = string.len(input)
- local left = len
- local cnt = 0
- local arr = {0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}
- while left ~= 0 do
- local tmp = string.byte(input, -left)
- local i = #arr
- while arr[i] do
- if tmp >= arr[i] then
- left = left - i
- break
- end
- i = i - 1
- end
- cnt = cnt + 1
- end
- return cnt
- end
- -- 计算utf8字符串字符数, 中文按两个字符计算
- function stringTool.utf8len_ChineseInTwo( str )
- local len = 0
- local currentIndex = 1
- while currentIndex <= #str do
- local char = string.byte(str, currentIndex)
- local charLength = stringTool.chsize(char)
- currentIndex = currentIndex + charLength
- if charLength > 2 then
- len = len + 2
- else
- len = len +1
- end
- end
- return len
- end
- --截取字符串,按字符截取
- -- str: 要截取的字符串
- -- startChar: 开始字符下标,从1开始
- -- numChars: 要截取的字符长度
- function stringTool.utf8sub( str, startChar, numChars )
- local startIndex = 1
- while startChar > 1 do
- local char = string.byte(str, startIndex)
- startIndex = startIndex + stringTool.chsize(char)
- startChar = startChar - 1
- end
-
- local currentIndex = startIndex
-
- while numChars > 0 and currentIndex <= #str do
- local char = string.byte(str, currentIndex)
- currentIndex = currentIndex + stringTool.chsize(char)
- numChars = numChars -1
- end
- return str:sub(startIndex, currentIndex - 1), numChars
- end