写一个包含非ASCII字符的字符串 - 仅当string是变量时才会出错?

时间:2013-09-28 17:44:47

标签: c++ string visual-c++

我正在尝试将包含非ASCII字符的字符串写入文件,例如“maçã”,“pé”等。

我现在正在做这样的事情:

_setmode(_fileno(stdout), _O_U16TEXT);

//I added the line above recently to the question,
//but it was in the code before, I forgot to write it
//I also included some header files, to be able to do that
//can't really remember which, if necessary I'll look it up.


wstring word=L"";
wstring file = L"example_file.txt"
vector<wstring> my_vector;

wofstream my_output(file);

while(word != L".")
{
 getline(wcin, word);
 if(word!= L".")
   my_vector.pushback(word);
}

for(std::vector<wstring>::iterator j=my_vector.begin(); j!=my_vector.end(); j++)
    {
        my_output << *j << endl;
//element pointed by iterator going through the whole vector

        my_output << L("maçã pé") << endl;
    }
my_output.close();

现在,如果我输入“maçã”,“pé”和“。”作为单词(只有前两个存储在向量中), 文件的输出很奇怪:

  • 我输入的字词(存储在变量中)显得很奇怪:“ma‡Æ”和“p”,
  • 直接存储在代码中的单词看起来非常正常“maçãpé”;

我尝试使用wcin >> word而不是getline(wcin, word)并写入控制台而不是文件,结果是相同的:写入变量字符串错误,直接在代码中写入字符串。

我找不到发生这种情况的原因,所以我们将非常感谢任何帮助。

编辑:我在Windows 7中使用Visual C ++ 2010

编辑2 :添加了一行代码,我错过了。 (在开头)

编辑3: 遵循SigTerm的建议,我意识到问题在于输入:wcin和getline都没有将正确格式化的字符串变为变量{{1} }。所以,问题是,你知道造成这种情况的原因或解决方法吗?

3 个答案:

答案 0 :(得分:3)

尝试加入

#include <locale>

并在main的开头写上

std::locale::global(std::locale(""));

答案 1 :(得分:1)

Windows使编码混乱,因为控制台通常使用“OEM”代码页,而GUI应用程序使用“ANSI”代码页。每个都随着使用的Windows的本地化版本而变化。在美国Windows上,OEM代码页为437,ANSI代码页为1252。

记住以上几点,将流设置为正在使用的语言环境可以解决问题。如果在控制台中工作,请使用控制台的代码页:

wcin.imbue(std::locale("English_United States.437"));
wcout.imbue(std::locale("English_United States.437"));

但请记住,大多数代码页都是单字节编码,因此只能理解256个可能的Unicode字符:

wstring word;
wcin.imbue(std::locale("English_United States.437"));
wcout.imbue(std::locale("English_United States.437"));
getline(wcin, word);
wcout << word << endl;
wcout << L"maçã pé" << endl;

在控制台上返回:

maça pé
maça pé

Code page 437不包含ã

如果您:

可以使用控制台中的代码页1252
  • 问题chcp 1252
  • 使用类似Consolas或Lucida Console的TrueType控制台字体。
  • 改为使用English_United States.1252填充流。

写入文件有类似的问题。如果在记事本中查看该文件,它将使用ANSI代码页来解释文件中的字节。因此,即使控制台应用程序使用代码页437,如果使用437代码页编写,记事本也会错误地显示该文件。在代码页1252中编写文件也没有帮助,因为这两个代码页不解释同一组Unicode代码点。这个问题的一些答案是获取不同的文件查看器,如Notepad ++,或者以UTF-8编写支持所有Unicode字符的文件。

答案 2 :(得分:0)

您遇到的问题与described here相反。

核心原因是相同的:“ASCII” 1 范围128-256中的字符标准化程度低于32-127范围内的字符。大多数Windows应用程序,无论是使用“Unicode”还是“ANSI”字符串,都使用Unicode指定的代码和字符之间的相同映射。但是,由于大多数历史原因,控制台使用单独的代码到字符的映射,通常称为“代码页”。使用的确切表取决于Windows的语言和配置。对于美国英语计算机,这是OEM 437 Code Page

当您在控制台中键入ç时,您确实输入了字符代码135,因为这是在控制台使用的437代码页中分配给该字符的代码。 Windows的其余部分将Unicode表中描述的字符代码解释为字符

您可以使用OemToChardocumentation here)将通过控制台输入的文本转换为Unicode编码中的相应字符串。

有关其他背景信息,请参阅我的answer here


1 是的,这个范围是技术而非ASCII,但足够接近。我也在使用通常的非正式(和技术上错误的)Unicode定义。