为啥 wprintf 在 Linux 上将 Unicode 中的俄语文本音译成拉丁语?
Posted
技术标签:
【中文标题】为啥 wprintf 在 Linux 上将 Unicode 中的俄语文本音译成拉丁语?【英文标题】:Why does wprintf transliterate Russian text in Unicode into Latin on Linux?为什么 wprintf 在 Linux 上将 Unicode 中的俄语文本音译成拉丁语? 【发布时间】:2021-04-06 05:11:18 【问题描述】:为什么下面的程序
#include <stdio.h>
#include <wchar.h>
int main()
wprintf(L"Привет, мир!");
print "女贞,先生!"在 Linux 上?具体来说,为什么它将 Unicode 中的俄语文本音译为拉丁语,而不是将其转码为 UTF-8 或使用替换字符?
在 Godbolt 上演示此行为:https://godbolt.org/z/36zEcG
非宽版本 printf("Привет, мир!")
按预期打印此文本(“Привет, мир!”)。
【问题讨论】:
出于好奇,为什么还要在 Linux 上使用wchar
?
没有理由使用wchar_t
,因为它是不可移植的。我在回答另一个 SO 问题时遇到了这种“有趣”的行为:***.com/a/65480111/471164,
在我的系统中,它只打印??????, ???!
。你能检查一下/usr/share/i18n/locales/C
,看看里面有没有以translit
开头的规则吗?
@Heinzi,如果有兴趣,您可以在 Godbolt 上查看语言环境 - 问题中有一个链接。
【参考方案1】:
因为宽字符的转换是根据当前设置的语言环境完成的。默认情况下,C 程序总是以“C”语言环境开始,它只支持 ASCII 字符。
您必须先切换到任何俄语或 UTF-8 语言环境:
setlocale(LC_ALL, "ru_RU.utf8"); // Russian Unicode
setlocale(LC_ALL, "en_US.utf8"); // English US Unicode
或当前系统区域设置(这可能是您需要的):
setlocale(LC_ALL, "");
完整的程序将是:
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main()
setlocale(LC_ALL, "ru_RU.utf8");
wprintf(L"Привет, мир!\n");
至于您的代码在其他机器上按原样运行 - 这是由于 libc 在那里的运行方式。一些实现(如 musl)不支持非 Unicode 语言环境,因此可以无条件地将宽字符转换为 UTF-8 序列。
【讨论】:
当我在有或没有setlocale(LC_ALL, "ru_RU.utf8")
或setlocale(LC_ALL, "")
的godbolt上运行它时,它会逐字打印Privet, mir!
。
但是为什么要音译呢?它是否记录在某处?
@Jabberwocky 您的计算机上是否安装了“ru_RU.utf8”语言环境?如果没有,那么设置将失败。使用""
(默认语言环境),它可能是 UTF-8。任何 unicode 语言环境都可以。
@vitaut 我不确定,但我认为在没有语言环境的情况下输出这些字符是非法的,libc 可能可以做任何它想做的事情。音译是产生有效且仍然可读的输出的好方法。
@Jabberwocky 那么您使用的是什么语言环境?如果您在美国,请尝试“en_US.utf8”。【参考方案2】:
为什么它将 Unicode 中的俄语文本音译为拉丁语,而不是将其转码为 UTF-8 或使用替换字符?
因为您的程序的起始语言环境是默认语言环境,即C
语言环境。所以它将宽字符串转换为C
语言环境。 C
语言环境不处理 UTF-8 或任何 unicode,因此您的标准库最好将宽字符转换为 C
语言环境中使用的一些基本字符集。
您可以将语言环境更改为任何 UTF-8 语言环境,程序应输出 UTF-8 字符串。
注意:(在我知道的实现中)FILE
流的编码已确定并保存在时间选择流方向(宽与正常)。请记住在使用stdout
(即this 与this)进行任何操作之前设置语言环境。
【讨论】:
以上是关于为啥 wprintf 在 Linux 上将 Unicode 中的俄语文本音译成拉丁语?的主要内容,如果未能解决你的问题,请参考以下文章
Linux 上的 wprintf UTF16(应该是 UTF8)?
为啥 Microsoft.Build.Evaluation 在 64 位 PC 上将 $(ProgramFiles) 评估为“c:\program files”?