Table of Contents
<a id="org653e67d"></a>
提綱
<a id="orgaa23837"></a>
思路
<a id="org5477300"></a>
中文Unicode
<a id="org04343d8"></a>
Unicode和UTF8的聯(lián)系
<a id="org6082b9e"></a>
常見特殊字符
<a id="org536118c"></a>
過濾特殊字符
<a id="org228c7a2"></a>
思路
常見的特殊字符有很多,查了很多資料,沒找到特殊字符的Unicode編碼范圍,即使找到了也難以保證覆蓋了全部。因此只能從非的角度考慮, 實現(xiàn)目標(biāo)是留下操作系統(tǒng)支持的可作為文件名的字符。
<a id="org8e4ca1e"></a>
中文Unicode編碼
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="org-left" />
<col class="org-left" />
<col class="org-left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">字符集</th>
<th scope="col" class="org-left">字?jǐn)?shù)</th>
<th scope="col" class="org-left">Unicode編碼</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">基本漢字</td>
<td class="org-left">20902字</td>
<td class="org-left">4E00-9FA5</td>
</tr>
<tr>
<td class="org-left">基本漢字補充</td>
<td class="org-left">74字</td>
<td class="org-left">9FA6-9FEF</td>
</tr>
<tr>
<td class="org-left">擴展A</td>
<td class="org-left">6582字</td>
<td class="org-left">3400-4DB5</td>
</tr>
<tr>
<td class="org-left">擴展B</td>
<td class="org-left">42711字</td>
<td class="org-left">20000-2A6D6</td>
</tr>
<tr>
<td class="org-left">擴展C</td>
<td class="org-left">4149字</td>
<td class="org-left">2A700-2B734</td>
</tr>
<tr>
<td class="org-left">擴展D</td>
<td class="org-left">222字</td>
<td class="org-left">2B740-2B81D</td>
</tr>
<tr>
<td class="org-left">擴展E</td>
<td class="org-left">5762字</td>
<td class="org-left">2B820-2CEA1</td>
</tr>
<tr>
<td class="org-left">擴展F</td>
<td class="org-left">7473字</td>
<td class="org-left">2CEB0-2EBE0</td>
</tr>
<tr>
<td class="org-left">康熙部首</td>
<td class="org-left">214字</td>
<td class="org-left">2F00-2FD5</td>
</tr>
<tr>
<td class="org-left">部首擴展</td>
<td class="org-left">115字</td>
<td class="org-left">2E80-2EF3</td>
</tr>
<tr>
<td class="org-left">兼容漢字</td>
<td class="org-left">477字</td>
<td class="org-left">F900-FAD9</td>
</tr>
<tr>
<td class="org-left">兼容擴展</td>
<td class="org-left">542字</td>
<td class="org-left">2F800-2FA1D</td>
</tr>
<tr>
<td class="org-left">PUA(GBK)部件</td>
<td class="org-left">81字</td>
<td class="org-left">E815-E86F</td>
</tr>
<tr>
<td class="org-left">部件擴展</td>
<td class="org-left">452字</td>
<td class="org-left">E400-E5E8</td>
</tr>
<tr>
<td class="org-left">PUA增補</td>
<td class="org-left">207字</td>
<td class="org-left">E600-E6CF</td>
</tr>
<tr>
<td class="org-left">漢字筆畫</td>
<td class="org-left">36字</td>
<td class="org-left">31C0-31E3</td>
</tr>
<tr>
<td class="org-left">漢字結(jié)構(gòu)</td>
<td class="org-left">12字</td>
<td class="org-left">2FF0-2FFB</td>
</tr>
<tr>
<td class="org-left">漢語注音</td>
<td class="org-left">43字</td>
<td class="org-left">3105-312F</td>
</tr>
<tr>
<td class="org-left">注音擴展</td>
<td class="org-left">22字</td>
<td class="org-left">31A0-31BA</td>
</tr>
<tr>
<td class="org-left">〇</td>
<td class="org-left">1字</td>
<td class="org-left">3007</td>
</tr>
</tbody>
</table>
其中只需要考慮基本漢字字符集即可。
<a id="org0b2350d"></a>
根據(jù)字符的UTF8編碼獲取Unicode
UTF8和Unicode的關(guān)系網(wǎng)上資料很多, 在此不再贅述,簡而言之,中文的UTF8編碼都是三個字節(jié),1110xxxx 10xxxxxx 10xxxxxx, 剩余的16位正好放下Unicode編碼的兩個字節(jié),因此只要取出這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);
<a id="orgd97edca"></a>
需要過濾掉的特殊字符
- ASCII中Windows不支持作為文件名的字符正則: [\\\\/:*?\"<>|%s+ ]
- 兩個字節(jié)的UTF
- UTF編碼在四個字節(jié)及四個字節(jié)以上的字符
可以使用此頁面內(nèi)的特殊字符進行測試: https://wenku.baidu.com/view/fddf6408844769eae009ed14.html?re=view
<a id="orgbda98be"></a>
代碼實現(xiàn)
-- 過濾中文特殊字符
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