如何在C ++中读取重音字符并将其与isalnum一起使用?

时间:2015-12-19 01:18:49

标签: c++ input ascii diacritics strchr

我用法语编程,因此,我需要使用重音字符。我可以通过使用输出它们 #include <locale>setlocale(LC_ALL, ""),但在阅读重音字符时似乎有问题。以下是我为展示问题所做的简单示例:

#include <locale>
#include <iostream>

using namespace std;

const string SymbolsAllowed = "+-*/%";

int main()
{
    setlocale(LC_ALL, "");    // makes accents printable

    // Traduction : Please write a string with accented characters
    // 'é' is shown correctly :
    cout << "Veuillez écrire du texte accentué : ";

    string accentedString;
    getline(cin, accentedString);

    // Accented char are not shown correctly :
    cout << "Accented string written : " << accentedString << endl;

    for (unsigned int i = 0; i < accentedString.length(); ++i)
    {
        char currentChar = accentedString.at(i);

        // The program crashes while testing if currentChar is alphanumeric.
        // (error image below) :
        if (!isalnum(currentChar) && !strchr(SymbolsAllowed.c_str(), currentChar))
        {
            cout << endl << "Character not allowed : " << currentChar << endl;
            system("pause");
            return 1;
        }
    }

    cout << endl << "No unauthorized characters were written." << endl;

    system("pause");
    return 0;
}

以下是程序崩溃前的输出示例

Veuillez écrire du texte accentué : éèàìù
Accented string written : ʾS.?—

我注意到Visual Studio的调试器显示我写了一些不同于它输出的东西:

[0] -126 '‚'    char
[1] -118 'Š'    char
[2] -123 '…'    char
[3] -115 ''     char
[4] -105 '—'    char

显示的错误似乎表明只能使用介于-1和255之间的字符,但根据ASCII table我在上面示例中使用的重音字符的值< strong>不要超过此限制。

弹出错误对话框的图片Error message: Expression: c >= -1 && c <= 255

有人可以告诉我我做错了什么或给我一个解决方案吗?先感谢您。 :)

2 个答案:

答案 0 :(得分:1)

  1. char是您系统上的签名类型(实际上,在许多系统上),因此其值范围为-128到127.代码在128到255之间的字符看起来像负数,如果它们存储在char中,这实际上是调试器告诉您的内容:

    [0] -126 '‚'    char
    

    那是-126,而不是126.换句话说,130或0x8C。

  2. isalnum和朋友将int作为参数,其中(如错误消息所示)被约束为值EOF(系统上为-1)并且范围0-255。 -126不在此范围内。因此错误。您可以转换为unsigned char,或者(如果它适用于Windows,可能更好),使用双参数std::isalnum in <locale>

  3. 由于完全逃避我的原因,Windows似乎在CP-437中提供控制台输入,但处理CP-1252中的输出。这两个代码页的高半部分完全不同。因此,当您键入é时,它会从CP-437以130(0xC2)的形式发送到您的程序,但是当您将相同的字符发送回控制台时,它会根据CP-1252打印为(低) )打开单引号(看起来很像逗号,但不是)。这样就不行了。您需要将输入和输出放在同一代码页上。

  4. 我对Windows不太了解,但您可以在MS docs中找到一些有用的信息。该页面包含指向Windows特定功能的链接,这些功能设置输入和输出代码页。

  5. 有趣的是,程序源代码中的重音字符似乎是CP-1252,因为它们打印正确。如果您决定退出代码页1252 - 例如,通过采用Unicode - 您也必须修复源代码。

答案 1 :(得分:1)

使用is*to*函数,您确实需要将输入转换为unsigned char,然后再将其传递给函数:

if (!isalnum((unsigned char)currentChar) && !strchr(SymbolsAllowed.c_str(), currentChar)) {

虽然您正在使用它,但我建议您不要使用strchr,并切换到以下内容:

std::string SymbolsAllowed = "+-*/%";

if (... && SymbolsAllowed.find(currentChar) == std::string::npos)

虽然您已经了解它,但您可能会忘记甚至听到<{1}}函数的。你永远不应该在C ++中使用它。在这种情况下(退出exit),您应该main。否则,抛出异常(如果要退出程序,请在return中捕获异常并从那里返回)。

如果我写这篇文章,我的工作总体上会有所不同。 main已经有了完成循环尝试完成的大部分内容的功能,因此我设置std::string以包含所有您想要允许的符号,然后只搜索它不包含的任何内容:

symbolsAllowed