如何在Windows控制台上输出Unicode字符串

已经有一些与这个问题有关的问题.我认为我的问题有所不同,因为我没有实际的问题,我只是出于学术兴趣.我知道 Windows的UTF-16的实现有时与Unicode标准(例如排序规则)相反,或者与UTF-16相比更接近于旧的UCS-2,但是由于“UTF-16”简单.

背景:在Windows中,所有内容都是UTF-16.无论您是处理内核,图形子系统,文件系统还是其他任何内容,都会传递UTF-16字符串. Unix中没有区域设置或字符集.为了兼容中世纪版本的Windows,有一个名为“代码页”的东西已经过时但仍然被支持. AFAIK,只有一个正确的和不过时的功能将字符串写入控制台,即WriteConsoleW,它采用UTF-16字符串.此外,类似的讨论也适用于输入流,我也将忽略它.

但是,我认为这代表了Windows API中的一个设计缺陷:有一个通用的函数可以用来写入所有的流对象(文件,管道,控制台…),称为WriteFile,但是这个函数是面向字节的,t接受UTF-16字符串.该文档建议使用WriteConsoleW进行控制台输出(面向文本的)和WriteFile(其他所有其它的字节方向).由于控制台流和文件对象都由内核对象句柄表示,并且控制台流可以重定向,因此必须调用一个函数,以便每次写入标准输出流时,检查句柄是否表示控制台流或文件,从而打破多义词. OTOH,我认为Windows在文本字符串和原始字节之间的分隔(在许多其他系统如JavaPython中镜像)在概念上优于Unix的char *方法,忽略编码,并且不区分字符串和字节数组.

所以我的问题是:在这种情况下该怎么办?为什么即使在微软自己的图书馆里也没有解决这个问题呢? .NET框架和C和C库似乎都遵守过时的代码页模型.您将如何设计Windows API或应用程序框架来规避此问题?

我认为一般的问题(这并不容易解决)是所有的图书馆都假定所有的流都是面向字节的,并在其上面实现面向文本的流.但是,我们看到,Windows在操作系统级别上确实有特殊的面向文本的流,而且这些库无法应对.所以无论如何,我们必须对所有标准库进行重大改变.一个快速而肮脏的方式是将控制台视为只接受一个编码的特殊的面向字节的流.这仍然需要C和C标准库必须规避,因为它们不实现WriteFile / WriteConsoleW开关.那是对的吗?

我/我们在大多数(跨平台)应用程序/项目中使用的一般策略是:我们只是在任何地方使用UTF-8(我的意思是真正的标准).我们使用std :: string作为容器,我们只将所有内容解释为UTF8.而且我们也以这种方式处理所有文件IO,即我们期望UTF8并保存UTF8.在我们从某个地方获取字符串的情况下,我们知道它不是UTF8,我们将其转换为UTF8.

我们绊倒WinUTF16的最常见的情况是文件名.所以对于每个文件名处理,我们将始终将UTF8字符串转换为WinUTF16.而另一方面,如果我们搜索文件的目录.

控制台在我们的Windows构建中并没有被真正使用(在Windows构建中,所有的控制台输出都被包装到一个文件中).由于我们拥有UTF8,所以我们的控制台输出也是UTF8,这对大多数现代系统都是好的.而且Windows控制台日志文件的内容也是UTF8,Windows上的大多数文本编辑器都可以读取文件,而不会出现问题.

如果我们更多地使用WinConsole,如果我们关心所有特殊字符都正确显示,我们可能会写一些自动管道处理程序,我们安装在fileno = 0和真正的stdout之间,这将使用WriteConsoleW,如您所建议的(如果真的没有更简单的方法).

如果您想知道如何实现这种自动管道处理器:我们已经为所有类似POSIX的系统实现了这样的事情.该代码可能在Windows上不起作用,但我认为应该可以将其移植.我们目前的管道处理器类似于T恤.即如果你做一个cout<< “Hello”<< endl,它将都打印在stdout和某些日志文件中.看看the code如果你有兴趣这样做.

相关文章

windows无法连接到wifi怎么办
文章浏览阅读2.2k次,点赞6次,收藏20次。在我们平时办公工作...
文章浏览阅读1k次。解决 Windows make command not found 和...
文章浏览阅读3.2k次,点赞2次,收藏6次。2、鼠标依次点击“计...
文章浏览阅读1.3w次。蓝光版属于高清版的一种。BD英文全名是...
文章浏览阅读974次,点赞7次,收藏8次。提供了更强大的功能,...