【问题标题】:How can I read accented characters in C++ and use them with isalnum?如何在 C++ 中读取重音字符并将它们与 isalnum 一起使用?
【发布时间】:2016-03-25 18:58:49
【问题描述】:

我正在用法语编程,因此,我需要使用重音字符。我可以通过使用输出它们 #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,我在上面的示例中使用的重音字符的值 不要超过这个限制

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

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

【问题讨论】:

  • ASCII 表的范围仅为 0-127。对于 unicode 字符,您需要使用wchar_t。顺便说一句,在您的系统中charsigned 类型,因此调试器将显示不在0-127 范围内的值的负值。备注:char 既不是signed char 也不是unsigned char
  • 使用 Unicode。不要使用语言环境。 stackoverflow.com/q/2849010/995714stackoverflow.com/q/2492077/995714

标签: c++ input ascii diacritics strchr


【解决方案1】:
  1. char 在您的系统上是有符号类型(实际上,在许多系统上),因此它的值范围是 -128 到 127。如果代码在 128 到 255 之间的字符存储在 @ 中,它们看起来就像负数987654326@,这实际上是你的调试器告诉你的:

    [0] -126 '‚'    char
    

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

  2. isalnum 和朋友们将int 作为参数,它(如错误消息所示)被限制为值EOF(系统上为-1)和范围0-255。 -126 不在此范围内。因此错误。您可以转换为unsigned char,或者(可能更好,如果它适用于Windows),使用两个参数std::isalnum in &lt;locale&gt;

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

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

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

【讨论】:

  • 我不确定您提到的 CP-437 输入和 CP-1252 输出。我默认看到的输入和输出都是 CP-437。
  • @jerry: 对 setlocale 的调用是否改变了输出但没有输入 cp?根据观察到的输出,输出 cp 必须为 1252...
  • 我想启动代码可能正在做某事,但我什么也没做,只是检索并打印出代码页。也许我应该用一个根本不使用/链接标准库的程序进行测试。
  • 我刚刚编写并运行了一个根本不使用或链接标准库的程序。它所做的只是检索控制台的 CP(输入和输出)并显示它们。两者都显示 437(Windows 7,以美国英语用户身份安装)。
  • @JerryCoffin:好的,我稍微编辑了我的答案。我认为对setlocale(LC_ALL, ""); 的调用是罪魁祸首,但我对此不是100% 有信心。而且OP大概是法国用户,可能涉及到不同的默认值。
【解决方案2】:

使用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)

当您使用它时,您可能应该忘记自己曾经听说过 exit 函数。你永远不应该在 C++ 中使用它。在这种情况下(从main 退出)你应该只是return。否则,抛出异常(如果要退出程序,请在main 中捕获异常并从那里返回)。

如果我在写这篇文章,我会以不同的方式完成这项工作。 std::string 已经有一个函数可以完成你的循环试图完成的大部分工作,所以我设置了 symbolsAllowed 以包含 all 你想要允许的符号,然后只需进行搜索对于它不包含的任何内容:

// Add all the authorized characters to the string:
for (unsigned char a = 0; a < std::numeric_limits<unsigned char>::max(); a++)
    if (isalnum(a) || isspace(a)) // you probably want to allow spaces?
        symbolsAllowed += a;

// ...

auto pos = accentedString.find_first_not_of(symbolsAllowed);
if (pos != std::string::npos) {
    std::cout << "Character not allowed: " << accentedString[pos];
    return 1;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    相关资源
    最近更新 更多