如何使用wcout显示L"أَبْجَدِيَّة عَرَبِيَّة‎中文"?

10
我想使用wcout显示一个包含阿拉伯语和中文的消息。
以下代码是正确的:
#include <iostream>

using namespace std;

int main()
{
    wcout.imbue(locale("chs"));
    wcout << L"中文"; // OK
}

然而,下面的代码无法正常工作:

#include <iostream>

using namespace std;

int main()
{
    wcout.imbue(locale(/* What to place here ??? */));
    wcout << L"أَبْجَدِيَّة عَرَبِيَّة‎中文"; // Output nothing. VC++ 2012 on Win7 x64
    // Why does the main advantage of unicode not apply here?
}

在采用unicode之后,我认为代码页的概念应该被废弃。

Q1. wout是如何显示这段文字的机制?

Q2. 作为一个基于unicode的操作系统,为什么Windows不支持在其控制台窗口中输出unicode字符?


3
以上代码有哪些问题? - Ivaylo Strandjev
1
也许可以在这里看一下:https://dev59.com/WHE95IYBdhLWcg3wCJRf - Ivaylo Strandjev
@Oleg,我想知道如何在纯C++中混合语言的情况下生成UNICODE输出。基于Windows API的解决方案不是我想要的。我想了解这样一个Unicode字符串输出到控制台的机制。 - xmllmx
1
你真正的问题是什么?你想在你的电脑上显示结果,还是想创建控制台应用程序,在每台Windows电脑上都显示相同的信息?后者是不可能的。如果你创建了一个使用其他人的应用程序,你应该考虑使用非控制台应用程序。即使在Windows NT 3.1时代(20多年前),控制台应用程序也被解释为遗留应用程序。主要设计目标是与旧应用程序兼容。这就是使用更早期世界存在的代码页的原因。 - Oleg
@xmllmx:不客气!很抱歉,但在控制台应用程序中使用_setmode_O_U16TEXT_O_U8TEXT_O_WTEXT确实足以启用Unicode模式。要能够看到结果,必须使用UNICODE代码页(在cmd中执行“chcp 65001”)。最后一个要求是在控制台中使用可以显示结果的字体,这对于普通计算机来说是最复杂的,因此唯一安全的方法将是将结果导出到文件中,这只在很少的情况下真正有用。 - Oleg
显示剩余12条评论
6个回答

5
默认情况下,CRT会将所有输出到文件的内容视为ANSI格式。您可以在程序开头加入以下代码来更改这一设置。
_setmode(_fileno(stdout), _O_WTEXT);

一个好的参考 @ http://www.siao2.com/2008/03/18/8306597.aspx

只是作为参考,大多数命令提示符都有双向语言支持的限制,而我所了解的是这种限制导致了这个问题。为什么不支持双向语言是我无法回答的。


@xmllmx 可能是你的字体问题。我尝试使用 Courier New,我可以看到阿拉伯文但看不到中文。 - Joel Rondeau
尝试将阿拉伯文本直接复制粘贴到终端中。这样可以告诉你字体是否支持该语言。 - Gort the Robot
1
首先要检查的是是否将其重定向到文件并获取所需的输出。如果是,则很可能是cmd提示符本身的字符编码限制。在stackoverflow上有许多关于此问题的参考资料。 - allen
2
那一定是原因所在。你的控制台字体可能不支持它们。 - n. m.
2
这不是关于Unicode的问题,而是关于Bidi的问题。 - Remus Rusanu
显示剩余5条评论

4
您无法使用标准C++工具来便携地打印宽字符串。
相反,您可以使用开源的{fmt}库来便携地打印Unicode文本。例如(https://godbolt.org/z/nccb6j):
#include <fmt/core.h>

int main() {
  fmt::print("أَبْجَدِيَّة عَرَبِيَّة‎中文");
}

打印
أَبْجَدِيَّة عَرَبِيَّة‎中文

这需要在MSVC中使用/utf-8编译器选项进行编译。
相比之下,在Linux上写入wcouthttps://godbolt.org/z/h9WKsY):
std::wcout << L"أَبْجَدِيَّة عَرَبِيَّة‎中文";

打印

???????????? ?????????????

除非您将全局区域设置切换为例如en_US.utf8。在Windows上存在类似的问题,没有标准的解决方法(您必须使用非标准CRT函数或Windows API)。

免责声明:我是{fmt}的作者。


C++ 20,std::wprint(L"中文")仍然输出空字符串,我不确定<format>是否等于<fmt>。 - huang

2

1
#include <iostream>
#include <io.h>
#include <fcntl.h>

int main() {
    _setmode(_fileno(stdout), _O_U16TEXT); // or _O_WTEXT
    std::wcout << L"أَبْجَدِيَّة عَرَبِيَّة‎中文" << std::endl;
}

http://www.cplusplus.com/forum/beginner/126557/


1
你可以尝试这个:
我假设你已经能够呈现中文纯文本。这意味着你有中文字体文件。
请使用纯阿拉伯文本进行尝试。如果您能够呈现,那就意味着您的系统中有阿拉伯字体。
但是,当您混合使用阿拉伯语和中文时,您需要强制选择一个具有两种字形集的字体文件。我认为wcout选择的默认字体文件没有阿拉伯字形。
我假设您可能会收到阿拉伯Unicode的方框。

0

在Windows上

我建议将wcout缓冲区重定向到文件以便查看结果,因为Windows命令提示符无法显示一些Unicode字体。
#include <iostream>
#include <fstream>                                                                                                                     

int main()
{
    std::locale myloc("en_US.UTF-8");
    std::locale::global(myloc);                                              

    std::wfilebuf wfbuf;
    wfbuf.open("result.txt", std::ios::out);
    std::wcout.rdbuf(std::addressof(wfbuf));   
                                                
    std::wcout << L"أَبْجَدِيَّة عَرَبِيَّة‎中文";   
 
    return 0;
}

在Linux上

方法1

#include <iostream>                                                                                                                        
                       
int main()
{
    std::ios::sync_with_stdio(false);// make wcout no longer depend on stdio
    std::locale myloc("en_US.UTF-8");                                           
    std::wcout.imbue(myloc);                                                    
    std::wcout << L"أَبْجَدِيَّة عَرَبِيَّة‎中文";   
 
    return 0;
}

方法二

#include <cstdio>                                                                                                                        
                       
int main()
{
    std::locale myloc("en_US.UTF-8");                                           
    std::locale::global(myloc);// can affect stdio's locale                                               
    wprintf(L"أَبْجَدِيَّة عَرَبِيَّة‎中文");  
 
    return 0;
}

方法三

#include <cstdio>                                                                                                                        
                       
int main()
{
    std::locale myloc("en_US.UTF-8");                                           
    std::locale::global(myloc);// can affect stdio's locale                                                                 
    std::wcout << L"أَبْجَدِيَّة عَرَبِيَّة‎中文";// wcout depend on stdio, it doesn't matter if wcout's locale still C locale.

    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接