一般在工作中会遇到中文字符的判断、截断、打码等需求,之前一直没有总结,虽然网上资料也多,今天在这里简单的总结一下。
1 .UTF-8简单描述
UTF-8 是 Unicode 的实现方式之一,其对应关系(编码规则)如下表所示:
Unicode 可以容纳100多万个符号
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。取值0-127,与标准ASCII 码一一对应。标准ASCII 码表见附录。
- 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
2 .UTF-8的中文字符编码如何生成
例如 将中
,龙
两个字从Unicode转换为UTF-8:
- 中 : Unicode 是
0x4E2D
(0100 1110 0010 1101
),根据上表,处于第三行范围内,UTF-8编码需要三个字节,格式为1110xxxx 10xxxxxx 10xxxxxx
。
将中
的Unicode 二进制填充进这个格式,得到11100100 10111000 10101101
,转换为十进制是228,184,173
print(string.char(228,184,173))
=>中
- 龙 : Unicode 是
0x9F99
(1001 1111 1001 1001
) ,同样处于第三行范围内。
UTF-8编码为11101001 10111110 10011001
(233,190,153
)print(string.char(233,190,153))
=>龙
3. lua判断字符是不是中文
通常来说,汉字范围从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()
- 原型:string.byte (s [, i [, j] ])
- 解释:函数返回字符s[i], s[i+1], ···, s[j]的内部数字编码(ASCII码),其中参数i的默认值是1,而参数j的默认值是i。
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