Я программирую на французском языке, и поэтому мне нужно использовать акцентированные символы. Я могу вывести их с помощью
#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
Может кто-нибудь сказать мне, что я делаю неправильно, или дать мне решение для этого? Заранее спасибо. 🙂
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
в <locale>
По причинам, которые меня полностью избегают, Windows, кажется, обеспечивает консольный ввод в CP-437 но обработка вывода в CP-1252. Верхняя половина этих двух кодовых страниц совершенно другая. Поэтому, когда вы печатаете é
, он отправляется в вашу программу как 130 (0xC2) из CP-437, но когда вы отправляете этот же символ обратно в консоль, он печатается в соответствии с CP-1252 как (низкая) открытая одинарная кавычка ‚
(который выглядит как запятая, но не так). Так что это не сработает. Вы должны получить ввод и вывод, чтобы быть на той же кодовой странице.
Я не знаю много о Windows, но вы можете найти полезную информацию в MS документы. Эта страница содержит ссылки на специфичные для Windows функции, которые устанавливают кодовые страницы ввода и вывода.
Интересно, что акцентированные символы в исходном коде вашей программы выглядят как CP-1252, так как они печатаются правильно. Если вы решите отойти от кодовой страницы 1252 — например, приняв Unicode — вам также придется исправить исходный код.
С 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;
}