簡體   English   中英

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

[英]Printing wchar_t to console in C++

我制作了一個簡單的程序,它將讀取 PS1 存儲卡二進制文件,並在 Visual Studio 中使用 C++ 在控制台中顯示其內容。 游戲標題在內存中以 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);

我現在的問題是我無法將 lTitleL 變量打印到控制台。 我試過 cout、wcout、printf、wprintf,我無法讓它們工作! 我知道 lTitleL 變量正確地保存了標題,因為我可以在調試器中看到它。 當我調用我嘗試過的任何打印函數時,根本沒有打印任何內容。 任何幫助,將不勝感激! 謝謝。

大編輯:

好的,這就是我的情況:

            // 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 將 Shift-JIS 輸入字符串轉換為寬字符。
  • 打印到控制台進行調試。
  • 現在的問題是 PS1 存儲卡以全角形式存儲所有字符,因此我使用 LCMapStringEX 將它們轉換為半角以獲得更好的輸出。
  • 打印到控制台進行調試。
  • 如果我很樂意使用 WriteConsoleW,這就足夠了,但如果不是,那么一個問題是某些標點符號的編碼很奇怪,並且使用 std::wcout 或 wprintf() 不能很好地打印。 例如,連字符存儲為 U+FF70 -“半角片假名-平假名延長音標”(轉換為半角后),無論使用哪種字體,這些都只顯示為問號(但是,它們確實打印正確使用 WriteConsoleW)。
  • 因此,我現在可以使用 WideCharToMultiByte,使用 UTF-8 代碼頁來獲取使用 std::wcout 或 wprintf() 很好地打印到控制台的字符串版本。 但是,我必須同時調用 SetConsoleCP(65001) 和 SetConsoleOutputCP(65001) 才能正確打印,否則多字節字符(如我提到的 U+FF70)將逐字節打印。
  • 最后,要顯示任何不尋常的字符,我需要選擇一種可以顯示它們的字體。 我發現在我的控制台中使用默認字體的唯一字體是 NSimSun 和 SimSun-ExtB,其他字體似乎都沒有包含日語字符(至少對於 U+FF70 字符)。

為了幫助可視化輸出,以下是使用 NSimSun 字體的控制台屏幕截圖:

在此處輸入圖片說明

在這里使用 Consolas 字體:

在此處輸入圖片說明

現在我的問題是:我不是特別喜歡 NSimSun 字體,是否還有其他字體看起來更像 Consolas 字體,它們確實包含全/半寬日語字符的所有字形? 如果是這樣,我如何將它們打包到我的控制台應用程序中以使其可移植?

謝謝!

Windows 對在控制台上打印 Unicode 的支持有限。 使用MessageBoxW(0, lTitleL, 0, 0)測試您的轉換,只要轉換正常,就可以保證成功。

要打印到控制台窗口,您必須調用_setmode(_fileno(stdout), _O_U16TEXT); 為了打印超出 ASCII 范圍的字符。

堅持使用std::wcoutwprintf(L"%s", str)

如果控制台不支持正確的字體,還有一個問題。 你必須嘗試不同的字體。 請參閱下面的示例。 還可以考慮使用具有自動清理功能的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