【Lua】Windows下的UTF-8支持的吐槽

发布时间 2023-11-02 01:16:34作者: ThankVinci

疯狂擦汗

发现离上篇随笔已经过去快四个月了,而我已经工作快三个月了,有点懒哈。

对编码标准的吐槽

首当其冲需要吐槽的就是Windows的编码支持,不同的国家语言使用不同的编码,虽然底层用的是UTF16,但除了Windows外也没有别的系统用宽字符了,一些写好的API在Windows上就提供了一份窄字符串和一份宽字符串的两种版本,在cmd中进行交互时用了当前的本地代码页,在这种环境下保存文件的编码也默认保存成本地代码页的编码,导致不同国家的用户文本的编码不能达成统一的标准。

新手刚入门编程就遇到的最普遍的问题就是乱码,我刚入门的时候,编译个C程序输出中文也乱码、Java也乱码、html也乱码,很多人应该都踩过这种坑,不然网络上不会出现那些教人改成GBK编码的方法,因为都想着解决燃眉之急,所以治标不治本,直接了当地说,Windows就是一坨具有兼容性的。。

扫盲

给可能在Windows上没用过宽字符类型的童鞋扫个盲,因为毕竟很多书或者视频都是直接const char起步的,如果不是Windows编程的老人家,可能对宽字符也不是很了解。

宽字符类型即wchar_t,这个是只在Windows上具有的类型,Windows上具有窄字符串和宽字符串的概念,宽字符串在Windows上就是小端的UTF16,因此Windows的底层实际上是支持Unicode的,这也是Windows系统在不同国家语言中能正常操作名字奇奇怪怪的文件的原因,窄字符串最终会转成宽字符串,窄字符串就是我们传统认知中的ASCII、GBK、UTF8编码,其中ASCII编码被GBK、UTF8编码所兼容,而GBK与UTF8字符集并不兼容了,比方说GBK使用两个字节来编码一个中文字符,而UTF8编码使用三个字节进行编码:假设一个UTF8编码的文本中包含了“你好”,占6个字节,如果强行以GBK编码打开就会变成3个2字节的GBK字符乱码。也就是说,系统并不识别你的UTF8字符串,它会把这个字符串当作GBK字符串来进行解析,然后把这个GBK字符串转成宽字符串,然后输出这个乱码,或者打开这个文件名,当以作为文件名打开时,就会找不到文件,也因此我使用lua执行ffmpeg命令出现了问题,一开始我也是要解决燃眉之急就使用iconv进行编码转换,但是UTF-8中存在一些字符编码在GBK中是没有映射的,会丢失一些数据,这个我当然是无法接受的。

纠结之处

四个月前,我用宽字符串去写了一个临时替代用的os_execute(当时没有想太多,而且编码转换的函数也没用对,可能会发生内存越界或者内存泄漏)算是解决了燃眉之急,当时并没有重写print和io的操作,而现在我想做这件事情,就得统筹规划好。

lua是通过C语言实现的,lua中也有自己的字符串类型,当然是通过char类型进行封装的,所以为了一个Windows去重写整个lua的字符串类型以及调用的相关函数是不值当的,我有没有这个能力是一码事,值不值得这么做又是另一码事,而且其他平台并不需要这些给Windows提供的兼容代码,把一个#ifdef插进代码不好看不说,还特别影响对代码的阅读,污染了代码(这是我的看法啊),而且到时候如果lua官方更新了源码,我要更新就得把在lua源码中改过的地方进行对比,很不方便。(事实上我luaByCMake项目中包含的lfs模块已经被我魔改成兼容Windows了,这主要是考虑到lfs更新概率比较低,且代码是真的不多,所以我就放心大胆地改了,改完效果还可以)

思来想去我觉得还是使用插件式的补丁,因为lua的一个模块实际上就是一个具有函数的表,如果键值相等的话就可以把值替换掉,用这种原理就可以把我自己写的函数替换掉lua原生的函数,这样就不会破坏到lua的代码,并且这么写的话,虽然代码更新时我还得对照,但由于额外的模块中只包含了我魔改的函数,所以对照的难度就不是很大了。

修改的内容

前面说过,我不想改到lua的源代码,所以lua的string类型我是绝对不会动的,因为lua的string类型虽然是char数组,但是它并不以'\0'结尾,换言之就是一个字节流,既然是字节流,那么它是什么数据就不重要了,重要的是取出数据时要怎么操作,所以我修改的内容就是在每个C函数从栈中取出字符串指针(UTF8)后,将字符串转为宽字符串,并调用一些对应的宽字符串的API,再找到适合的地方去回收掉这块宽字符串的内存。

尾声

其实没什么尾声,就想讲一下我的体会,其实我写lua一开始的原因是我不想用python,我纯粹是因为卖课的厌恶这门语言,这很幼稚,当然反正只是批量执行个命令行而已什么脚本都行,使用lua的话还得在Windows上考虑UTF8的问题,python的话根本就不用去想这个问题,而且python还提供了很多的包可以用,我本来是打退堂鼓的,但是熟悉了lua语法和特性之后,我觉得还是在lua这里造轮子开心一点,虽然造的轮子都是自己在用,但是我很清楚我的脚本、模块都具有哪些功能,我可以自由地进行添加,而且lua可以调用CAPI,那我以后真的学会了opengl和ffmpeg就可以给lua封装API来使用了,这可能有点多余哈哈。