Ввод — Как я могу прочитать символы с акцентом в C ++ и использовать их с isalnum?

Я программирую на французском языке, и поэтому мне нужно использовать акцентированные символы. Я могу вывести их с помощью
#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 таблица значение акцентированных символов, которые я использовал в примере выше не превышать этот предел.

Вот изображение диалога ошибки это выскакивает: Сообщение об ошибке: Выражение: c> = -1 && с <= 255

Может кто-нибудь сказать мне, что я делаю неправильно, или дать мне решение для этого? Заранее спасибо. 🙂

2

Решение

  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 в <locale>

  3. По причинам, которые меня полностью избегают, Windows, кажется, обеспечивает консольный ввод в CP-437 но обработка вывода в CP-1252. Верхняя половина этих двух кодовых страниц совершенно другая. Поэтому, когда вы печатаете é, он отправляется в вашу программу как 130 (0xC2) из ​​CP-437, но когда вы отправляете этот же символ обратно в консоль, он печатается в соответствии с CP-1252 как (низкая) открытая одинарная кавычка (который выглядит как запятая, но не так). Так что это не сработает. Вы должны получить ввод и вывод, чтобы быть на той же кодовой странице.

  4. Я не знаю много о Windows, но вы можете найти полезную информацию в MS документы. Эта страница содержит ссылки на специфичные для Windows функции, которые устанавливают кодовые страницы ввода и вывода.

  5. Интересно, что акцентированные символы в исходном коде вашей программы выглядят как CP-1252, так как они печатаются правильно. Если вы решите отойти от кодовой страницы 1252 — например, приняв Unicode — вам также придется исправить исходный код.

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)

Пока вы в этом, вы, вероятно, должны забыть, что вы когда-либо даже услышанным из exit функция. Вы никогда не должны использовать его в C ++. В случае здесь (выход из main) ты должен просто return, В противном случае выдается исключение (и, если вы хотите выйти из программы, перехватите исключение в main и вернуться оттуда).

Если бы я писал это, я бы сделал работу несколько иначе в целом. std::string уже есть функция для выполнения большей части того, что пытается выполнить ваш цикл, поэтому я настроил symbolsAllowed включать все символы, которые вы хотите разрешить, затем просто выполните поиск чего-либо, что не содержит:

// 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;
}
1

По вопросам рекламы [email protected]