C++:使用平台无关的方式打印ASCII心形和钻石形

8

我正在开发一款纸牌游戏,希望打印出红桃、方块、黑桃和梅花的符号。我的目标平台将是Linux。

在Windows中,我知道如何打印这些符号。例如,要打印一个心形符号(在ASCII中),我写了...

// in Windows, print a ASCII Heart

#include <iostream>

using std::cout;
using std::endl;

int main()
{
 char foo = '\3';
 cout << heart << endl;
 system ( "PAUSE" );
 return 0;
}

然而,正如我所提到的,在Linux中不会打印出心形符号。是否有一个标准库可以用来在Linux和Windows中打印心形、方块、黑桃和红桃符号?到目前为止,我一直在研究Unicode,因为我的理解是这是普遍适用的。

4个回答

14
如果您想要一种便携的方式,那么您应该使用Unicode代码点(它们与定义好的字形相关联):
♠ U+2660 Black Spade Suit
♡ U+2661 White Heart Suit
♢ U+2662 White Diamond Suit
♣ U+2663 Black Club Suit
♤ U+2664 White Spade Suit
♥ U+2665 Black Heart Suit
♦ U+2666 Black Diamond Suit
♧ U+2667 White Club Suit

请记住,在ASCII字符集中,32以下的所有内容都是控制字符。它们有与之相关的含义,您无法保证得到一个字形或行为(即使大多数控制字符确实具有字形,尽管它们从未被设计为可打印)。但是,这并不是一个安全的赌注。

但是,使用Unicode需要适当的字体和编码支持,这可能在类Unix系统上成为问题,也可能不是问题。

至少在Windows上,如果控制台设置为光栅字体(因此不支持Unicode或任何其他当前设置的OEM代码页以外的东西),则上述某些代码点将映射到您正在输出的ASCII控制字符字形。这仅适用于黑色变体,因为白色变体没有等效物。


12
"♠U+2660黑色宇航服"是我最近看到的比较有趣的打字错误之一。 - Jerry Coffin
@Jerry:[呃,我讨厌那个@],已经修复了 :-)。我缺乏咖啡因,我想 :-)。而且我更经常打“space”而不是“spade”,所以我的手指在没有与我的眼睛协商是否正确的情况下就开始工作了 :-)。 - Joey
Rössel:你是如何在回答中“输入”这些符号的? - Lazer
@eskay:字符映射和复制/粘贴。如果我事先知道代码点,我就可以在PowerShell中简单地执行[char]2662并从那里复制。或者我使用RichEdit的实例(Word、其他各种程序),输入代码点值,然后按Alt+X/Alt+C。 - Joey

8

在Linux上,您几乎总是可以将UTF-8编码写入标准输出(stdout),并且Unicode字符将会显示得非常好。

#include <iostream>

const char heart[] = "\xe2\x99\xa5";

int main() {
    std::cout << heart << '\n';
    return 0;
}

您可以在网站上查找Unicode字符的UTF-8编码,例如fileformat.info(搜索该页面的“UTF-8(hex)”)。
另一种方法是使用宽字符。您首先需要调用setlocale来设置环境。然后只需使用wchar_t代替char,使用wcout代替cout即可。
#include <iostream>
#include <clocale>

const wchar_t heart[] = L"\u2665";

int main() {
    setlocale(LC_ALL, "");
    std::wcout << heart << L'\n';
    return 0;
}

有没有任何专家对此有问题?我想将来可能会发现它很有用。 - James Morris
setlocale + wcout 绝对是最标准的做法。主要的烦恼在于除了标准库之外,库通常希望你传递 char 字符串而不是 wchar_t。因此,你必须编写函数来进行相互转换,并在适当的时候调用它们。这最终感觉有点像官僚主义。:-\ - Jason Orendorff
+1:这个回答比被接受的那个更加详细。 - Kornel Kisielewicz
+1 是因为实际告诉了 OP 如何正确使用 Unicode。我不怎么用 C/C++,所以我只记得应该使用 L"" 字符串字面量,但其他的不太清楚。盲目使用 UTF-8 的第一个建议几乎可以被点踩,尽管这是我的个人看法。宽字符 API 应该会为您处理转换,而您则盲目地假设区域设置使用 UTF-8。 - Joey
“盲目使用UTF-8的建议几乎可以被点踩,尽管如此。” 这是公平的。 从某种意义上说,几乎每个不调用setlocale并使用宽字符以及localeconv来显示数字的程序都是有问题的。 - Jason Orendorff

1

顶部答案现已过时或不正确。

梅花、方块、红心、黑桃的ASCII码分别为'\5','\4','\3','\6'


1

这不是关于库的问题,而是关于你所使用字体的代码页的问题。

如果你正在运行的终端所使用的字体当前代码页中没有心形和方块图案,那么没有任何库能帮助你——你必须使用图形。

如需进一步阅读,可以尝试在Unicode表中找到相关信息——然而,Unicode终端很少见……即使你有一个Unicode字体,也不能保证它会包含卡片图案。

总之:一切都取决于字体,没有可靠的便携式方法可以实现它,除非提供自己的字形。


这是我第一次听到“代码页”的概念。现在我会去了解一下。非常感谢。 - different
1
Unicode是一种实现这一点的便携式方式 - 至少在支持Unicode的系统上(你知道哪些操作系统不支持吗?)。您可以特定地输出代表心形图案的字符。字体中的字形支持可能会破坏这一点,但这并不影响心形图案出现的事实。然而,当使用像OP一样的控制字符时,您绝对无法保证可移植性。 - Joey
你可以特别输出代表心形的字符。-- 当然,如果用户的字体中没有该字符,那么输出它有什么意义呢? - Kornel Kisielewicz
1
代码页并没有特别的标准化,这意味着你会遇到相同的可移植性问题。Unicode是标准的,并且确实有合适的符号。不幸的是,它可能无法在任何给定的平台上工作,但这是开始的最佳位置。 - David Thornley
1
Kornel:Unicode 是关于信息表示的。字体支持实际上只是一个副任务。首要任务是表示内容。在这里,你有一个字符,它说:“嘿,我是一个填充的心形”,而不是一个字符,它说:“嘿,我是一个控制字符,用于结束文本,但如果你对我好一点,我也可以显示为一个字形。在某些系统上,我可能会出现为一个填充的心形。”此外,套装符号现在已经存在于大多数流行的字体中。操作系统应该没有问题找到合适的字体。 - Joey
显示剩余5条评论

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