6

我在用 C++ 将 unicode 写入文件时遇到问题。我想用我自己的扩展名向文件中写入一些笑脸,您可以通过键入 ALT+NUMPAD(2) 来获得这些笑脸。我可以通过创建一个字符并为其分配 '\2' 的值来在 CMD 上显示它,它会显示一个笑脸,但它不会将其写入文件。

这是我的程序的代码片段:

ofstream myfile;
myfile.open("C:\Users\My Username\test.exampleCodeFile");
myfile << "\2";
myfile.close();

它会写入文件,但不会显示我想要的。我会向您展示它显示的内容,但 StackOverflow 不会让我显示该角色。提前致谢。

4

3 回答 3

8

您必须使用 Unicode 来指定要显示的字符。控制台中由字节表示的字符02h由代码页 437 ( cp437 ) 转换为 Unicode 字符U+263B。使用以 UTF-8 保存的带有 BOM 的源文件可以更轻松地使用 Unicode,因为您可以粘贴或键入所需的字符,而无需使用 Unicode 转义码。

对于文件流,需要将流配置为 UTF-8。有多种方法可以做到这一点,这取决于编译器,但使用 Visual Studio 2012,源代码保存在 UTF-8 w/BOM 中,还有一些谷歌搜索:

#include <locale>
#include <codecvt>
#include <fstream>
#include <iostream>
#include <io.h>
#include <fcntl.h>
using namespace std;

int main()
{
    const std::locale utf8_locale = std::locale(std::locale(), new std::codecvt_utf8<wchar_t>());
    wofstream f(L"sample.txt");
    f.imbue(utf8_locale);
    f << L"\u263b我是美国人。我叫马克。" << endl;

    _setmode(_fileno(stdout),_O_U16TEXT);
    wcout << L"\u263b我是美国人。我叫马克。" << endl;
}

sample.txt在记事本中查看的内容:

☻我是美国人。我叫马克。

十六进制转储(正确的 UTF-8):

E68891E698AFE7BE8EE59BBDE4BABAE38082E68891E58FABE9A9ACE5858BE380820D0A

输出到控制台剪切并粘贴在这里。没有正确字体的每个汉字的视觉显示是�,但字符显示正确粘贴到 SO 或记事本中。

☻我是美国人。我叫马克。
于 2013-04-09T23:51:21.457 回答
5

ALT+NUMPAD2 与 ASCII 字符 2 不同,后者是您的代码写入文件的内容。ALT 代码是 DOS 处理非 ASCII 字符的方式。CMD.COM 为 ALT+NUMPAD2 显示的字形实际上是 Unicode 代码点 U+263B “BLACK SMILING FACE”。作为 Unicode 字符,您最好使用 UTF-8 或 UTF-16 对文件进行编码,例如:

ofstream myfile;
myfile.open("C:\\Users\My Username\\test.txt");
myfile << "\xEF\xBB\xBF"; // UTF-8 BOM
myfile << "\xE2\x98\xBB"; // U+263B
myfile.close();

.

ofstream myfile;
myfile.open("C:\\Users\\My Username\\test.txt");
myfile << "\xFF\xFE"; // UTF-16 BOM
myfile << "\x3B\x26"; // U+263B
myfile.close();

这两种方法都在记事本中显示笑脸(前提是您使用支持笑脸的字体),因为它首先读取 BOM,然后根据该信息相应地解码 Unicode 代码点。

于 2013-04-09T22:55:17.333 回答
3

您使用的与 Unicode 完全相反。控制台使用 8 位代码页运行,西方机器上的默认代码页是代码页 437。它与旧的 IBM PC 字符 ROM 的字符集相匹配,并且是大多数遗留 DOS 程序所期望的代码页。第一组字符代码,代码 0 到 8 如下所示:

在此处输入图像描述

请注意代码 0x02 的笑脸,即您在控制台上看到的笑脸。您可以在这篇Wikipedia 文章中查看其余的字形。8 位字符编码的一个令人讨厌的问题是它们太多了。记事本使用不同的代码页读取您的文件。默认情况下,在西欧和美洲的机器上是Windows-1252 。该页面没有任何控制代码的字形,这就是您在记事本中看不到笑脸的原因。

处理代码页是一个令人头疼的问题。这就是发明Unicode的原因。

可以将控制台切换到 Unicode 代码页。然而,它仍然必须是 8 位编码,这是支持输出重定向的控制台程序的另一个遗留问题。这使得正确的选择 utf-8。chcp 65001您可以在启动程序之前通过键入从控制台本身切换。或者您可以在您的代码中执行此操作,调用SetConsoleOutputCP(CP_UTF8);.

您必须注意的另一个不幸的细节是,您还需要更改用于控制台的字体。默认字体是 TERMINAL,这是一种传统字体,旨在显示 IBM PC 字形,但不了解 Unicode。使用系统菜单切换(按Alt+Space,Properties),选择不多但Consolas或Lucinda Console都适合。

现在您可以显示 Unicode,这是 Remy 介绍的另一回事。

于 2013-04-09T23:48:29.520 回答