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