简体   繁体   English

在 C++ 中将 wchar_t 打印到控制台

[英]Printing wchar_t to console in C++

I have made a simple program that will read in a PS1 Memory Card binary file and display it's contents in the console using C++ in Visual Studio.我制作了一个简单的程序,它将读取 PS1 存储卡二进制文件,并在 Visual Studio 中使用 C++ 在控制台中显示其内容。 The game titles are encoded in the memory in Shift-JIS format, so I used the MultiByteToWideChar function to convert them:游戏标题在内存中以 Shift-JIS 格式编码,所以我使用 MultiByteToWideChar 函数来转换它们:

            // Converting Shift-JIS
            char lTitle[65];
            strcpy_s(lTitle, mymemcard[lFrame - 1].title);

            int lTitleChars = MultiByteToWideChar(932, 0, lTitle, -1, NULL, 0);
            wchar_t* lTitleL = new wchar_t[lTitleChars];
            MultiByteToWideChar(932, 0, lTitle, -1, lTitleL, lTitleChars);

My problem is now that I can't get the lTitleL variable to print to the console.我现在的问题是我无法将 lTitleL 变量打印到控制台。 I've tried cout, wcout, printf, wprintf, I can't get them to work!我试过 cout、wcout、printf、wprintf,我无法让它们工作! I know that the lTitleL variable proiperly holds the title since I can see it in the debugger.我知道 lTitleL 变量正确地保存了标题,因为我可以在调试器中看到它。 When I call any of the print functions I've tried, simply nothing gets printed.当我调用我尝试过的任何打印函数时,根本没有打印任何内容。 ANy help would be appreciated!任何帮助,将不胜感激! Thanks.谢谢。

BIG EDIT:大编辑:

OK, so here's where I am with this:好的,这就是我的情况:

            // Converting Shift-JIS to UTF-8 //
            ///////////////////////////////////
            // First, convert the multi-byte Shift-JIS format into wide characters
            strcpy_s(lTitle, mymemcard[lFrame - 1].titleMB);
            lTitleChars = MultiByteToWideChar(932, 0, lTitle, -1, NULL, 0);
            wchar_t* lTitleFW = new wchar_t[lTitleChars];
            MultiByteToWideChar(932, 0, lTitle, -1, lTitleFW, lTitleChars);
            wprintf(L"FW, WriteConsoleW - ");
            WriteConsoleW(consoleHandle, lTitleFW, lTitleChars, NULL, 0);
            wprintf(L"\n");
            // Memory card seems to store all characters in their "Full Width" forms, we need to convert them to Half-Width so they display nicely in the console
            wchar_t* lTitleHW = new wchar_t[lTitleChars];
            LCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_HALFWIDTH, lTitleFW, lTitleChars, lTitleHW, lTitleChars, NULL, NULL, 0);
            wprintf(L"HW, WriteConsoleW - ");
            WriteConsoleW(consoleHandle, lTitleHW, lTitleChars, NULL, 0);
            wprintf(L"\n");
            wprintf(L"HW, wprintf()     - %s\n", lTitleHW);
            // Now we can convert it into UTF-8 format to allow it to be printed using std::cout
            // This step isn't necessary as we could call WriteConsoleW on lTitleHW instead, but why not
            lTitleChars = WideCharToMultiByte(CP_UTF8, 0, lTitleHW, -1, NULL, 0, NULL, NULL);
            char* lTitleUTF = new char[lTitleChars];
            WideCharToMultiByte(CP_UTF8, 0, lTitleHW, -1, lTitleUTF, lTitleChars, NULL, NULL);
            strcpy_s(mymemcard[lFrame - 1].titleUTF, lTitleUTF);
            wprintf(L"UTF, wprintf()    - %S\n\n", lTitleUTF);
            delete[] lTitleFW;
            delete[] lTitleHW;
            delete[] lTitleUTF;
            ///////////////////////////////////
  • MultiByteToWideChar to get the Shift-JIS input string into wide chars. MultiByteToWideChar 将 Shift-JIS 输入字符串转换为宽字符。
  • Print that to console for debugging.打印到控制台进行调试。
  • Problem now is that the PS1 Memory Card stores all characters in their full-width forms, so I use LCMapStringEX to convert them to half-width for nicer output.现在的问题是 PS1 存储卡以全角形式存储所有字符,因此我使用 LCMapStringEX 将它们转换为半角以获得更好的输出。
  • Print that to console for debugging.打印到控制台进行调试。
  • This is enough if I am happy to use WriteConsoleW, but if not then one problem is that certain punctuations are encoded strangely and don't print nicely using std::wcout or wprintf().如果我很乐意使用 WriteConsoleW,这就足够了,但如果不是,那么一个问题是某些标点符号的编码很奇怪,并且使用 std::wcout 或 wprintf() 不能很好地打印。 For example, hyphens are stored as U+FF70 - "Halfwidth Katakana-Hiragana Prolonged Sound Mark" (after converting to half-width) and these just show up as question marks regardless of the font being used (they do, however, print correctly using WriteConsoleW).例如,连字符存储为 U+FF70 -“半角片假名-平假名延长音标”(转换为半角后),无论使用哪种字体,这些都只显示为问号(但是,它们确实打印正确使用 WriteConsoleW)。
  • So, I can now use WideCharToMultiByte, using the UTF-8 code page to get a version of the string that prints nicely to the console using std::wcout or wprintf().因此,我现在可以使用 WideCharToMultiByte,使用 UTF-8 代码页来获取使用 std::wcout 或 wprintf() 很好地打印到控制台的字符串版本。 I do, however, have to call both SetConsoleCP(65001) and SetConsoleOutputCP(65001) for them to print properly, otherwise the multi-byte chars (like the U+FF70 I mentioned) get printed byte-by-byte.但是,我必须同时调用 SetConsoleCP(65001) 和 SetConsoleOutputCP(65001) 才能正确打印,否则多字节字符(如我提到的 U+FF70)将逐字节打印。
  • Lastly, for any of the unusual characters to show up, I need to have a font selected that can display them.最后,要显示任何不寻常的字符,我需要选择一种可以显示它们的字体。 The only ones I have found that work in the default fonts in my console are NSimSun and SimSun-ExtB, none of the others seems to contain the Japanese characters (at least for the U+FF70 character).我发现在我的控制台中使用默认字体的唯一字体是 NSimSun 和 SimSun-ExtB,其他字体似乎都没有包含日语字符(至少对于 U+FF70 字符)。

To help visualise the output of this, here's a screenshot of the console using the NSimSun font:为了帮助可视化输出,以下是使用 NSimSun 字体的控制台屏幕截图:

在此处输入图片说明

And here with Consolas font:在这里使用 Consolas 字体:

在此处输入图片说明

Now for my question: I don't particularly like the NSimSun font, are there any others out there that look more like the Consolas font that do contain all the glyphs for the full/half width Japanese characters?现在我的问题是:我不是特别喜欢 NSimSun 字体,是否还有其他字体看起来更像 Consolas 字体,它们确实包含全/半宽日语字符的所有字形? If so, how can I package them into my Console app so that it's portable?如果是这样,我如何将它们打包到我的控制台应用程序中以使其可移植?

Thanks!谢谢!

Windows has limited support for printing Unicode on console. Windows 对在控制台上打印 Unicode 的支持有限。 Test your conversion by using MessageBoxW(0, lTitleL, 0, 0) which is guaranteed to succeed, as long as the conversion was okay.使用MessageBoxW(0, lTitleL, 0, 0)测试您的转换,只要转换正常,就可以保证成功。

To print to console window, you have to call _setmode(_fileno(stdout), _O_U16TEXT);要打印到控制台窗口,您必须调用_setmode(_fileno(stdout), _O_U16TEXT); in order to print characters out of ASCII range.为了打印超出 ASCII 范围的字符。

Stick with std::wcout or wprintf(L"%s", str)坚持使用std::wcoutwprintf(L"%s", str)

There is an additional problem if the console does not support the right font.如果控制台不支持正确的字体,还有一个问题。 You have to try different fonts.你必须尝试不同的字体。 See example below.请参阅下面的示例。 Also consider using std::wstring which has automatic cleanup.还可以考虑使用具有自动清理功能的std::wstring

#include <iostream>
#include <string>
#include <io.h> 
#include <fcntl.h> 
#include <Windows.h>

int main()
{
    const wchar_t *src = L"ABC 日本語";

    int size;
    size = WideCharToMultiByte(932, 0, src, -1, NULL, 0, 0, 0);
    std::string temp(size, 0);
    WideCharToMultiByte(932, 0, src, -1, temp.data(), size, 0, 0);

    size = MultiByteToWideChar(932, 0, temp.data(), -1, 0, 0);
    std::wstring dst(size, 0);
    MultiByteToWideChar(932, 0, temp.c_str(), -1, dst.data(), size);

    _setmode(_fileno(stdout), _O_U16TEXT);

    wprintf(L"%s\n", dst.c_str());

    //Try with different font
    CONSOLE_FONT_INFOEX font = { sizeof(font) };
    HANDLE hcout = GetStdHandle(STD_OUTPUT_HANDLE);
    GetCurrentConsoleFontEx(hcout, FALSE, &font);
    wcscpy_s(font.FaceName, L"MS Gothic");
    SetCurrentConsoleFontEx(hcout, FALSE, &font);
    std::wcout << dst << "\n";

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM