C++ 如何使用Windows.h读取和显示扩展ASCII符号

C++ 如何使用Windows.h读取和显示扩展ASCII符号,c++,character-encoding,console,C++,Character Encoding,Console,我正在开发一个控制台游戏,它使用ASCII符号作为像素。此游戏的地图存储在.txt文件中: ████████████████ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █

我正在开发一个控制台游戏,它使用ASCII符号作为像素。此游戏的地图存储在
.txt
文件中:

████████████████
█              █
█              █
█              █
█              █
█              █
█              █
█              █
█              █
█              █
█              █
█              █
█              █
█              █
█              █
████████████████
要显示地图,我正在逐行从文件
demo.txt
读取地图,并将每个字符写入
CHAR\u INFO*屏幕

void setScreen(const char* layoutFile, const char* levelDataFile) {
        std::ifstream levelData(levelDataFile);
        levelData >> width >> height;
        field = {0, 0, (SHORT)width, (SHORT)height};
        screen = new CHAR_INFO[width * height];
        levelData.close();

        std::ifstream layout(layoutFile);                            //reading from a file `demo.txt`
        std::string line;

        for (int j = 0; j < height; j++) {
            getline(layout, line);
            for(int i = 0; i < width; i++) {
                screen[j * width + i].Char.AsciiChar = line[i];      //writing each character of a line to screen
                screen[j * width + i].Attributes = BACKGROUND_GREEN;
            }
        }
        layout.close();
    }
但问题是
显示为
,输出如下所示:

����������������
���
���
���
���
���
���
���
���
���
���
���
���
���
���
����������������
我试过一些东西:

  • SetConsoleOutputCP(CP\u UTF8);SetConsoleCP(CP_UTF8)
  • SetConsoleCutputCP(1251)
  • setlocale(LC_ALL,”)
  • std::locale::global(std::locale(std::locale::empty(),新std::codevt_utf8))
根据评论:

文件编码为
UTF-8

这是一个巨大的不同。您不仅没有处理ASCII字符(值高达127),甚至没有处理扩展ASCII字符(值高达255)。您正在处理Unicode,特别是字符号9608(又称U+2588)。这远远超出了单个
char
所能代表的范围。然而,当您从
行[i]
赋值时,您正在存储单个
字符

的UTF-8表示法█'由三个字节组成:
0xE2
0x96
0x88
。这就是为什么您的输出在电路板的左侧显示三个“未知字符”符号,而在右侧则没有。这些“未知字符”符号来自一个UTF-8字符的三个字节。然后,除了在
width-3
空格后停止复制字符外,您将在
width-2
空格后再添加三个“未知字符”。因此,你永远不会遇到你的董事会的“真正”的权利边界。(检查
行的长度
并将其与
宽度
进行比较–对于中间行,您应该看到
行.size()
宽度+4
。对于第一行和最后一行,您应该看到
行.size()
3*宽度

部分解决方案是使用
Char.UnicodeChar
而不是
Char.ascihar
。然而,
UnicodeChar
只有两个字节,所以它不能保存三字节的UTF-8编码。您可能必须转换为UTF-16。如果您只需要几个字符,那么查找表可以作为一般解决方案。通过口述等效项将文件中的字符更改为真正的ASCII字符。例如,您可以说
“#”
表示一个完整的块。它的优点是只包含一个字节,因此您的逻辑基本上是有效的。您只需要添加一个翻译函数,比如

WCHAR转换(字符c)
{
开关(c){
大小写“#”:返回u'\0x2588';//完整块(█)
//等等。
}
返回c;//如果不需要翻译
}
然后,在存储地图数据时,可以调用此转换,如中所示

screen[j * width + i].Char.UnicodeChar = convert(line[i]);

最后一步是确保您的控制台需要UTF-16.Oh,并使用
WriteConsoleOutputW()
而不是
WriteConsoleOutputA()

文件是如何编码的?您是否尝试过使用
std::wfstream
而不是
std::fstream
?@alterigel是的,我尝试过使用
std::wifstream
,结果是一样的。文件是用
UTF-8
@JaMiT编码的,我也尝试过
setconsolecutcp(437)
,但没有改变
screen[j * width + i].Char.UnicodeChar = convert(line[i]);