不常用,查了又忘,遇到時又抓狂,記錄下,疑問請留言。內容來自經驗總結,盲人摸象,不系統,不正確。果然忘了,解決方案在最后一段。
環境
Lua 5.3(Lua文檔/文件UTF8),Win 10(CP936),ZeroBrane Studio(CP936)。
字符對應編碼。
字符(符號/character)與編碼(code)相互映射。字符-編碼->編碼、編碼-解碼->字符。
編碼可展現為數值(十進制、十六進制等),以字節(byte)為單位,一個字符的編碼為一個或多個字節。
從編碼的角度,可稱為碼表。
從字符被組織的角度,可稱為字符集。
字符在碼表中的編碼,被稱為編碼位置(簡稱碼位/code point/code position)。
一個字符可以被多個碼表描述,對應多種編碼。
參考:漢字字符集編碼查詢;中文字符集編碼:GB2312、BIG5、GBK、GB18030、Unicode
字符"·"的GB2312編碼:無,BIG5編碼:A150,GBK編碼:A1A4,GB18030編碼:A1A4,Unicode編碼:B7
字符"中"的GB2312編碼:D6D0,BIG5編碼:A4A4,GBK編碼:D6D0,GB18030編碼:D6D0,Unicode編碼:4E2D
Windows系統中碼表稱為代碼頁。
CHCP命令可查看、設置系統代碼頁。
命令chcp.com位於C:\Windows\System32\chcp.com。
此路徑被包含於PATH環境變量下,可在命令行CMD、Lua Shellos.execute使用。
Unicode,一個具體的碼表,包含所有字符及其編碼。
Lua文檔/文件/代碼中的字面字符(字面量/literal string)受Lua文件編碼的影響(稱為硬編碼)。
如,字符"·"在utf8編碼的文件中編碼為194,183,在CP936編碼的文件中編碼為161,164。
Lua中可在字面量字符串中嵌入顯式地指定編碼(byte單元),形如"\xXX"(十六進制)或"\ddd"(十進制)。
則,在utf8編碼的文件中,有assert("·"=="\194\183");在CP936編碼的文件中,有assert("·"=="\161\164")。
類似的,可在字面量字符串中嵌入顯式指定的utf8(二次編碼的Unicode)編碼,形如"\u{XXX}"。
參見Lua手冊,3.1 – Lexical Conventions
The UTF-8 encoding of a Unicode character can be inserted in a literal string
以上嵌入的編碼不經過Lua文件字符解析,不受指定的文件編碼的影響。
代碼頁(CodePage/CP)一個個具體的碼表,各自包含一定范圍的字符及其編碼。
此一定范圍的字符是包含所有字符的Unicode的子集。
代碼頁中的字符是Unicode的子集,但其編碼不一定與Unicode編碼相同。
如中文字符集(代碼頁/CP936),包含中文環境涉及的字符,英文字符、中文字符等,其中英文字符的代碼頁編碼或與Unicode編碼一致,而中文字符的編碼不一致。
各代碼頁中的字符是Unicode的子集(描述的字符范圍較Unicode小),進而,存儲空間小、編碼/解碼時間短。
叫做代碼頁,是因為定義的各代碼頁是按數字編號的。CP1、CP2、..CP936..、CP65000、CP65001。
其中CP0為當前設定的系統/環境代碼頁,CP65001為UTF-8(參見如下utf-8)。
GB2312/GBK是不同版本的中國標准(國標)碼表。
GBK版本更高,兼容GB2312。
GBK被Unicode采納收錄到CP936。
其他還有更新的GB18030(收錄於CP54936)。
utf-8是壓縮/再編碼/重編碼/二次編碼/轉換方法。
把固定長度的某編碼轉換為一個或多個8位二進制單元的變長度編碼。
codepoint/unicode與utf8的轉換是雙向等價可逆的。
參考如下不同庫(github pure lua 庫1、庫2)中的函數名稱:
codepoint_to_utf8(codepoint)、utf8_to_codepoint(string,index);
unicode.encode、unicode.decode;
utf8_to_unicode(srcstr)、unicode_to_utf8(srcstr)。
UTF8(僅?)用於Unicode。codepoint為任意編碼(或特指Unicode?)
codepoint_to_utf8'·'報錯'out of range'?CP936不能轉utf8?
相關搜索:
PHP開發中編碼問題探討_跡憶博客(UTF-8被誤判為CP936)
php cp936轉utf8編碼轉換亂碼問題的解決方案_南通SEO-CSDN博客(作為latin1//IGNORE再轉UTF8)
詭異的 CP936 編碼無法轉換成 UTF-8 - V2EX(不要看print的結果,看原始HEX)
CP936、UTF8、Unicode相互關系
UTF8與Unicode可以靠算法相互轉換。UTF8可以看作Unicode的壓縮形式。
CP936與Unicode是不同的碼表,需要查表轉換。
如Unicode.org-CP936描述了CP936編碼與Unicode編碼(及Unicode字符名的對應關系)。
不同編碼值有各自的特征,可以通過掃描編碼值推斷出可能的編碼方式,但不完全准確。
如(以上提及的第三方庫)utf8.validate(str, byte_pos)可以驗證字符串是否為utf8編碼。
Lua中的編碼
如:utf8編碼下,有assert('·'=='\194\183' and '·'=='\u{b7}')。
string.byte (s [, i [, j]])
string.byte (char,1,#char)可以獲得字符char的編碼。
參見Lua手冊:
Returns the internal numeric codes of the characters s[i], s[i+1], ..., s[j].
其中,internal numeric codes即字符的編碼。
如utf8編碼的lua文件中的字符"·",string.byte ('·',1,#'·')得194,183;CP936編碼的此字符,得161,164。
string.char(byte,..)
為string.byte操作的逆操作,將編碼解碼為字符。
如string.char(194,183)所得字符在utf8下為"·",在其他編碼下無意義。
local char='·' local bytes={string.byte (char,1,#char)} assert(bytes[1]==194 and bytes[2]==183)--UTF8 194, 183 (0xA1A4) assert(string.char(table.unpack(bytes))==char)
print(...)
能接受uft8編碼或系統代碼頁(CP936)編碼輸入,並正確輸出字符。
如,print'\194\183'(utf8)、print'\161\164'(CP936)均輸出"·"。
貌似會自動/隱式地識別處理utf8編碼。故,不可用其檢查編碼問題。
ZeroBrane Studio(ZBS)調試中,會按文件編碼(此處為utf8)顯式字符串。
如,'\194\183'顯示為"·",'\161\164'顯示為'\161\164'。
部分Lua原生、第三方庫函數不支持utf8編碼。
如:io.open、io.popen、lfs.attributes、lfs.dir的輸入字符串需為系統活動代碼頁(CP936),不支持傳入/輸入utf8編碼的中文文件路徑;
而,lfs.dir的輸出(文件夾中文件、子文件夾的名字字符串)為系統激活代碼頁(CP936)。
assert(select(2,io.open[[G:\PathNotExist]]):find'No such file or directory') assert(select(2,io.open[[G:\中 文.txt]]):find'Invalid argument') assert(io.open'G:\\\xD6\xD0 \xCE\xC4.txt')--手動硬編碼指定 GBK/CP936 assert(select(2,io.open'G:\\\u{4e2d} \u{6587}.txt'):find'Invalid argument')--unicode
區分返回的錯誤信息'No such file or directory','Invalid argument'。
即,io.open函數的輸入參數需要CP936編碼,不可UTF8、Unicode編碼。
使用如下的gbk.dll、gutf8庫解決。
相關庫
perfgao/lua-resty-unicode - 碼雲 - 開源中國
unicode.encode'·'--\u00b7
unicode.decode'\\u00b7'--"·"
utf8.lua · Github,擴展lua標准字符串庫(正則等),使支持utf8,純Lua實現。
Egor-Skriptunoff/utf8_filenames.lua · Github
擴展Lua標准庫,使支持utf8編碼輸入。核心是其中的convert_from_utf8,可以提取用於擴展lfs。
starwing \ luagbk - GBK support for Lua · GitHub,高完成度,(gbk/CP936與UTF8的)編碼轉換
starwing \ luautf8 - GUTF-8 module for Lua 5.x · GitHub,高完成度,擴展lua標准字符串庫(正則等),加入其他UTF8專用函數
其他未歸入正文的參考鏈接:
utf 8 - How to convert windows-1256 to utf-8 in lua? - Stack Overflow