瑞典字符无法正确比较

时间:2014-04-06 11:13:05

标签: c++ if-statement statements setlocale

由于某种原因,在C ++中,if / else语句对我来说无法正常工作

问题是当一个变量等于右边(höger)时,它不会输出If语句,而是会继续执行else语句。如果我用'o'替换字母'ö'使其变为'hoger',那么if语句将起作用。因此,每当我写“höger”这个词时,它都不会转到if语句,而是转到else语句。但是,如果我将变量等于'hoger',然后我写'hoger',它将起作用。我如何才能使'höger'成为可能,而If语句却认出了它?就像瑞典字母不起作用一样。

我的代码如下:

#include <iostream>
#include <string>

using namespace std;


int main() {
    setlocale(LC_ALL,"");


    string test; // Define variabel
    cout << " Höger elle vänster"<<endl; // Right or left
    cin >> test;


    if(test == "höger") { // If right, then output this.

        cout <<"Du valde höger"<<endl;

    } 

    else if(test == "vänster") { // If left, then output this

        cout <<"Du valde vänster"<<endl;

    } else {

        // Do this

    }


}

5 个答案:

答案 0 :(得分:4)

问题几乎肯定与编码有关。

C / C ++语言规范不会自动处理7位ASCII以外的任何内容。 o-umlaut字符超出了该范围,确切的行为取决于源代码文件的编码。

最可能的可能性是ISO 8859-1,Windows ANSI-1252,UTF-8或Windows OEM 850.前两个编码此字符相同,但在其他每个字符中它都是不同的。

有关您正在使用的编码和工具集的更多信息,可能会提供更具体的诊断和建议。

[顺便说一句,如果C / C ++中的/ else语句运行得很好,谢谢。]


如果我们暂时假设这是Windows和Visual C ++,那么这就是你正在处理的事情。

  • Visual Studio中编写的源代码:代码页1252. o-umlaut字符的代码点为0xf6。
  • 从控制台读取键盘输入:代码页850. o-umlaut字符的代码点为0x94。

显然不是一场好比赛。但是,Visual Studio也可以很好地编辑许多编码中的源代码文件,包括UTF-8(带字节标记),UTF-16(宽字符)和代码页850.所以:

  • Visual Studio中编写的源代码:代码页850. o-umlaut字符的代码点是0x94。现在它有效。

您还可以使用CHCP命令更改控制台的代码页。

  • 将控制台更改为CHCP 1252,它可以正常工作。

标准要求编译器在读取源代码时的行为与执行字符集保持一致。见n3797 S2.2.5:

  

字符文字或字符串文字中的每个源字符集成员,以及每个转义符   字符文字或非原始字符串文字中的序列和通用字符名称将转换为执行字符集的相应成员

S2.3 / 3:

  

基本执行字符集和基本执行宽字符集应各自包含基本源字符集的所有成员,以及表示alert,backspace和回车符的控制字符,以及空字符(分别为null宽) character),其表示具有全零位。对于每个基本执行字符集,成员的值应是非负的并且彼此不同。在源和执行基本字符集中,上述十进制数字列表中0之后的每个字符的值应比前一个值大1。执行字符集和执行宽字符集是基本执行字符的实现定义的超集   set和基本执行宽字符集分别。执行字符集的成员值和其他成员集是特定于语言环境的。

n3797 S2.14.3 / 1:

  

不以u,U或L开头的字符文字是普通字符文字,也称为窄字符文字。包含在执行字符集中可表示的单个c-char的普通字符文字具有char类型,其值等于执行字符集中c-char的编码的数值。

n3297 S2.14.5 / 6:

  

不以encoding-prefix开头的字符串文字是普通字符串   文字,并用给定的字符初始化。

执行字符集是实现定义的。 Microsoft的声明需要C编译器的实现定义行为:http://msdn.microsoft.com/en-us/library/hx3yt8af.aspx。 [我找不到一个单独的C ++,所以我认为这适用于两者。]

The source character set is the set of legal characters that can appear in source files. For Microsoft C, the source character set is the standard ASCII character set.

对于语言律师的事情很抱歉,但这说明MSVC编译器独立于语言环境/编码并实现了8位ASCII,未指定代码页。显然,标准库函数可能需要知道编码用于各种目的,但这是另一个故事。


最后一点,Microsoft C编译器的历史可以追溯到30年前,因为在Windows之前。始终可以在代码页850中编写源代码并使其在控制台上正确运行,但需要小心处理扩展(8位)字符。很多人仍然这样做。这里的问题是用Windows-Ansi或Unicode编写的源代码和来自OEM(cp850)控制台的键盘输入。更改任何一个以使其正常工作。

答案 1 :(得分:1)

实际上,这个问题只会出现在Windows中,所以我假设是Windows。

然后问题是C ++ narrow扩展执行字符集 (1)(编码)与控制台窗口使用的编码不匹配。 “Narrow”指的是char类型。 “异常字符集”是C ++标准使用的正式术语,指的是对可执行文件中存储的文本假定的编码。编译器将源代码文字转换为此编码。它也被假定用于转换到/来自任何外部编码,例如转换为/来自控制台的编码。

enter image description here

使用Visual C ++,窄编码总是 Windows ANSI (2),无论源代码编码如何,除非您欺骗编译器。假设您使用的是Visual C ++,那么这就是您所知道的一种编码。

控制台窗口中的编码默认情况下是用于原始IBM PC的编码,在您的情况下可能代码页850 (原始IBM PC英文代码页437的西欧版本)。运行Windows命令解释程序cmd Windows密钥 + R ,键入cmd,确定)。输入chcp以检查当前代码页。键入chcp 1252以切换到Windows ANSI Western,这可能是您计算机上的Windows ANSI代码页。运行您的程序[.exe]文件,例如通过键入其完整路径,或者转到其目录并仅键入其名称,例如

[H:\dev\test\0046]
> cl /nologo /EHsc /GR encoding.cpp /Fe:b.exe
encoding.cpp

[H:\dev\test\0046]
> chcp & b
Active code page: 850
 Höger elle vänster
höger
                             No output here, didn't compare as equal.
[H:\dev\test\0046]
> chcp 1252
Active code page: 1252

[H:\dev\test\0046]
> b
 Höger elle vänster
höger
Du valde höger

[H:\dev\test\0046]
> _

...其中cl(原始“Lattice C”的缩写)是Visual C ++编译器。

您可以通过运行regedit更加永久地更改控制台代码页,转到此注册表项:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage

并在右侧窗格的列表中双击名为 OEMCP 的值(原始设备制造商代码页的缩写,指IBM PC),将其更改为1252,或更一般地,与ACP值相同的值,然后重新启动机器。

哦,还需要将控制台窗口字体更改为 TrueType字体,例如Lucida Console,因为默认情况下(仿真)位图字体只能与原始控制台一起正常工作代码页。您可以右键单击控制台窗口标题以获取菜单,选择[默认值],并配置默认字体,大小,颜色等。更改不会影响当前控制台窗口,但它们将应用于将来的控制台窗口,除了对于那些已单独配置(3)

此类控制台窗口配置的替代方法是使用 Console2 程序。如果这样做,那么在Windows 7及更高版本中一定要使用64位版本。否则,某些事情(例如调用64位程序的链接)将无效。


总结一下,你可以

  • 从命令解释程序运行程序(使用chcp更改代码页),或

  • 更加永久地更改控制台代码页,如上所述。

在任何一种情况下,将控制台窗口字体更改为TrueType字体都是一个好主意 - 是的,这会影响功能,而不仅仅是外观。

关于其他微软荒谬的注意事项:在Windows 7及更高版本中,控制台窗口中默认使用的“系统”字体实际上是 ,在幕后,是一个包含一万个字形的TrueType字体,但它已被使用模拟旧的16位Windows位图字体,具有相同的愚蠢限制,因此您仍然需要更改为其他一些TrueType字体...


(1)参见C ++ 11标准§2.3/ 3。

(2)“Windows ANSI”取决于Windows配置,始终是GetACP API函数指定的代码页。实际上,此函数从上面引用的注册表项/值中获取其值。但是,这主要是无证件

(3)在Windows XP中,Windows会询问您是否要保存单个控制台窗口配置。从Windows Vista开始,它保存,没有问题,也没有保存的信息。没有用于删除此类已保存配置的用户界面,但可以通过编程方式更改快捷方式文件和/或通过注册表编辑来删除它们,但这是一种不切实际且易于解决的问题。

答案 2 :(得分:0)

问题可能是非ASCII

我认为这个链接Handling Non-Ascii Chars in C++以及这篇长篇教程http://www.codeproject.com/Articles/38242/Reading-UTF-8-with-C-streams如果你仔细阅读它将会有所帮助。所有最好的

答案 3 :(得分:0)

我对您的代码所做的唯一更改如下:

// setlocale(LC_ALL, "");
char *l = setlocale(LC_ALL, NULL);
cout << "Current Locale: " << l << endl;

因为我没有“ISO”keyboard layout,所以我使用Alt code键入了我需要的字符。以下是我用于不同代码页的组合键。

以下是我在执行之间更改代码页时的输出 Output of program

答案 4 :(得分:0)

似乎问题是IDE编译时源文件的编码。如果您使用的是Visual Studio,则可以更改编码设置:

Here