Table of Contents
提纲
思路
中文Unicode
Unicode和UTF8的联系
常见特殊字符
过滤特殊字符
思路
常见的特殊字符有很多,查了很多资料,没找到特殊字符的Unicode编码范围,即使找到了也难以保证覆盖了全部。因此只能从非的角度考虑, 实现目标是留下操作系统支持的可作为文件名的字符。
中文Unicode编码
字符集字数Unicode编码
基本汉字20902字4E00-9FA5基本汉字补充74字9FA6-9FEF扩展A6582字3400-4DB5扩展B42711字20000-2A6D6扩展C4149字2A700-2B734扩展D222字2B740-2B81D扩展E5762字2B820-2CEA1扩展F7473字2CEB0-2EBE0康熙部首214字2F00-2FD5部首扩展115字2E80-2EF3兼容汉字477字F900-FAD9兼容扩展542字2F800-2FA1DPUA(GBK)部件81字E815-E86F部件扩展452字E400-E5E8PUA增补207字E600-E6CF汉字笔画36字31C0-31E3汉字结构12字2FF0-2FFB汉语注音43字3105-312F注音扩展22字31A0-31BA〇1字3007其中只需要考虑基本汉字字符集即可。
根据字符的UTF8编码获取Unicode
UTF8和Unicode的关系网上资料很多, 在此不再赘述,简而言之,中文的UTF8编码都是三个字节,1110xxxx 10xxxxxx 10xxxxxx, 剩余的16位正好放下Unicode编码的两个字节,因此只要取出这16位即可知道该字符的Unicode
Lua不支持位操作, b1 % 0xe0 代表 b1 & 0xe0,*212代表左移12位,依次类推
local b1 = string.byte(str, curIndex)
local b2 = string.byte(str, curIndex + 1)
local b3 = string.byte(str, curIndex + 2)
local unic = (b1 % 0xe0) * 2 ^ 12 + (b2 % 0x80) * 2 ^ 6 + (b3 % 0x80);
需要过滤掉的特殊字符
ASCII中Windows不支持作为文件名的字符正则: [\\\\/:*?\"<>|%s+ ]
两个字节的UTF
UTF编码在四个字节及四个字节以上的字符
代码实现
-- 过滤中文特殊字符
function filterInvalidChars(str)
local result = '';
local curIndex = 1;
-- 逐字检查, 符合要求则放入result
repeat
local curByte = string.byte(str, curIndex)
if curByte > 0 and curByte <= 127 then
result = result..string.sub(str, curIndex, curIndex)
curIndex = curIndex + 1
elseif curByte >= 192 and curByte <= 223 then
curIndex = curIndex + 2
elseif curByte >= 224 and curByte <= 239 then
-- 此处判断一些中文特殊字符
local b1 = curByte
local b2 = string.byte(str, curIndex + 1)
local b3 = string.byte(str, curIndex + 2)
local unic = (b1 % 0xe0) * 2 ^ 12 + (b2 % 0x80) * 2 ^ 6 + (b3 % 0x80)
if unic >= 0x4e00 and unic <= 0x9FA5 then
result = result..string.sub(str, curIndex, curIndex + 2)
end
curIndex = curIndex + 3
elseif curByte >= 240 and curByte <= 247 then
curIndex = curIndex + 4
else
logger:error('filter invalid chars error: '..str)
return str
end
until(curIndex >= #str);
return string.gsub(result, '[\\\\/:*?\"<>|%s+ ]', '');
end