不常用,查了又忘,遇到时又抓狂,记录下,疑问请留言。内容来自经验总结,盲人摸象,不系统,不正确。果然忘了,解决方案在最后一段。
环境
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:WindowsSystem32chcp.com。
此路径被包含于PATH环境变量下,可在命令行CMD、Lua Shellos.execute使用。
Unicode,一个具体的码表,包含所有字符及其编码。
Lua文档/文件/代码中的字面字符(字面量/literal string)受Lua文件编码的影响(称为硬编码)。
如,字符"·"在utf8编码的文件中编码为194,183,在CP936编码的文件中编码为161,164。
Lua中可在字面量字符串中嵌入显式地指定编码(byte单元),形如"xXX"(十六进制)或"ddd"(十进制)。
则,在utf8编码的文件中,有assert("·"=="194183");在CP936编码的文件中,有assert("·"=="161164")。
类似的,可在字面量字符串中嵌入显式指定的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('·'=='194183' 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'194183'(utf8)、print'161164'(CP936)均输出"·"。
貌似会自动/隐式地识别处理utf8编码。故,不可用其检查编码问题。
ZeroBrane Studio(ZBS)调试中,会按文件编码(此处为utf8)显式字符串。
如,'194183'显示为"·",'161164'显示为'161164'。
部分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:\xD6xD0 xCExC4.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