Windows 上的 UTF-8 和 Ada
UTF-8 on Windows with Ada
据我了解,默认情况下,Character
是Latin_1,Wide_Character
是UCS-2,Wide_Wide_Character
是UCS-4,但是GNAT可以已指定 pragma Wide_Character_Encoding(UTF8);
或 -gnatW8
,并且这些字符及其字符串将改为 UTF-8 编码。
至少在 Linux 和 FreeBSD 上,结果符合我的预期。但是 Windows 结果很奇怪。
对于 Wide 或 Wide_Wide 变体,一旦字符超出 ASCII 集,我就会出现乱码。我相信这被一些人称为 emojibake。所以我认为这是一个代码页问题。毕竟,Windows 中的默认代码页以及控制台主机加载的默认代码页是 437,这不是 UTF-8 代码页。 chcp 65001
现在不再是乱七八糟的额外字符,而是立即出现异常 raised ADA.IO_EXCEPTIONS.DEVICE_ERROR : a-ztexio.adb:1295
。查看异常发生的地方,好像是在fputc()
的putc
绑定中。但这是 Standard_Output,难道 EOF 永远不会发生吗?
是否有某种特殊考虑 Windows 需要?如何获得 UTF-8 输出?
编辑:
我尝试将输出通过管道传输到文本文件中。假定的 UTF-8 编码程序仍然会在文件中生成 emojibake。不知道为什么这会立即在控制台中抛出异常。
所以我尝试直接打开并写入文件而不是 console/pipe。奇怪的是,这完全可以正常工作。文字完全正确。
我从未在任何其他语言中看到过这种行为,所以应该仍然可以在控制台获得正确的 UTF-8,对吗?
根据其他人的评论和一些进一步的研究来确认,我很确定这是 Windows 控制台主机的缺陷。
编辑:不要听这个
不只是这里,在 Windows 控制台主机中描述的许多其他缺陷要么已修复,要么根本不存在。基于this document,我觉得它可能一直被误解得很深。 Windows 不会像对待文件一样对待控制台,很容易落入这个陷阱。
使用这个非常直接的代码,以及 Windows 在幕后需要和期望的东西...
只要使用 pragma Wide_Character_Encoding(UTF8);
或 -gnatW8
,它就会正确生成以下内容。
将此测试程序的输出通过管道传输到文件中可以正常工作。同样,将此测试程序的输出通过管道传输到另一个程序中也能正常工作。并且同样地,从管道输出中获取文件,并将其通过管道传输到另一个程序中,它应该可以正常工作。
Linux、Windows、
下的完整 UTF-8 行为
需要做的是双重的。在包初始化器中,控制台主机需要被告知它正在使用什么,这可以像这样完成。
然后通过fputwc
完成字符输出。根据 MS Docs fputc
不应该用于 Windows 上的 UNICODE,这是 GNAT 存在的部分问题。字符串输出和 character/string 输入都是相似的。
据我了解,默认情况下,Character
是Latin_1,Wide_Character
是UCS-2,Wide_Wide_Character
是UCS-4,但是GNAT可以已指定 pragma Wide_Character_Encoding(UTF8);
或 -gnatW8
,并且这些字符及其字符串将改为 UTF-8 编码。
至少在 Linux 和 FreeBSD 上,结果符合我的预期。但是 Windows 结果很奇怪。
对于 Wide 或 Wide_Wide 变体,一旦字符超出 ASCII 集,我就会出现乱码。我相信这被一些人称为 emojibake。所以我认为这是一个代码页问题。毕竟,Windows 中的默认代码页以及控制台主机加载的默认代码页是 437,这不是 UTF-8 代码页。 chcp 65001
现在不再是乱七八糟的额外字符,而是立即出现异常 raised ADA.IO_EXCEPTIONS.DEVICE_ERROR : a-ztexio.adb:1295
。查看异常发生的地方,好像是在fputc()
的putc
绑定中。但这是 Standard_Output,难道 EOF 永远不会发生吗?
是否有某种特殊考虑 Windows 需要?如何获得 UTF-8 输出?
编辑:
我尝试将输出通过管道传输到文本文件中。假定的 UTF-8 编码程序仍然会在文件中生成 emojibake。不知道为什么这会立即在控制台中抛出异常。
所以我尝试直接打开并写入文件而不是 console/pipe。奇怪的是,这完全可以正常工作。文字完全正确。
我从未在任何其他语言中看到过这种行为,所以应该仍然可以在控制台获得正确的 UTF-8,对吗?
根据其他人的评论和一些进一步的研究来确认,我很确定这是 Windows 控制台主机的缺陷。
编辑:不要听这个
不只是这里,在 Windows 控制台主机中描述的许多其他缺陷要么已修复,要么根本不存在。基于this document,我觉得它可能一直被误解得很深。 Windows 不会像对待文件一样对待控制台,很容易落入这个陷阱。
使用这个非常直接的代码,以及 Windows 在幕后需要和期望的东西...
只要使用 pragma Wide_Character_Encoding(UTF8);
或 -gnatW8
,它就会正确生成以下内容。
将此测试程序的输出通过管道传输到文件中可以正常工作。同样,将此测试程序的输出通过管道传输到另一个程序中也能正常工作。并且同样地,从管道输出中获取文件,并将其通过管道传输到另一个程序中,它应该可以正常工作。
Linux、Windows、
下的完整 UTF-8 行为需要做的是双重的。在包初始化器中,控制台主机需要被告知它正在使用什么,这可以像这样完成。
然后通过fputwc
完成字符输出。根据 MS Docs fputc
不应该用于 Windows 上的 UNICODE,这是 GNAT 存在的部分问题。字符串输出和 character/string 输入都是相似的。