我用法语编程,因此,我需要使用重音字符。我可以通过使用输出它们
#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
有人可以告诉我我做错了什么或给我一个解决方案吗?先感谢您。 :)
答案 0 :(得分:1)
char
是您系统上的签名类型(实际上,在许多系统上),因此其值范围为-128到127.代码在128到255之间的字符看起来像负数,如果它们存储在char
中,这实际上是调试器告诉您的内容:
[0] -126 '‚' char
那是-126,而不是126.换句话说,130或0x8C。
isalnum
和朋友将int
作为参数,其中(如错误消息所示)被约束为值EOF
(系统上为-1)并且范围0-255。 -126不在此范围内。因此错误。您可以转换为unsigned char
,或者(如果它适用于Windows,可能更好),使用双参数std::isalnum
in <locale>
由于完全逃避我的原因,Windows似乎在CP-437中提供控制台输入,但处理CP-1252中的输出。这两个代码页的高半部分完全不同。因此,当您键入é
时,它会从CP-437以130(0xC2)的形式发送到您的程序,但是当您将相同的字符发送回控制台时,它会根据CP-1252打印为(低) )打开单引号‚
(看起来很像逗号,但不是)。这样就不行了。您需要将输入和输出放在同一代码页上。
我对Windows不太了解,但您可以在MS docs中找到一些有用的信息。该页面包含指向Windows特定功能的链接,这些功能设置输入和输出代码页。
有趣的是,程序源代码中的重音字符似乎是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