Здравствуйте. Необходимо ограничить ввод пользователя только буквами и цифрами (на вход идут UTF-16 символы).
Раньше использовал iswalnum и все было хорошо. Но внезапно обнаружил, что на MacOSX эта функция перестала пропускать русские буквы. Почитал документацию — якобы, поведение зависит от текущей локали. И можно сделать так:
int main()
{
wchar_t c = L'\u13ad'; // the Cherokee letter HA ('Ꭽ')
std::cout << std::hex << std::showbase << std::boolalpha;
std::cout << "in the default locale, iswalnum(" << (std::wint_t)c << ") = "
<< (bool)std::iswalnum(c) << '\n';
std::setlocale(LC_ALL, "en_US.utf8");
std::cout << "in Unicode locale, iswalnum(" << (std::wint_t)c << ") = "
<< (bool)std::iswalnum(c) << '\n';
}
и все заработает.
Не заработало. Во-первых, мне не хочется переключать локаль в иную, чем стоит по умолчанию, во-вторых, даже с указанием локали "en_US.utf8" русские буквы ей все равно не нравятся (я вижу, что там en, но и "ru_RU.utf8" тоже не имеет эффекта). Да и при чем тут локаль, строго говоря? Мне просто нужно узнать класс символа, который однозначно определяется этими двумя байтами (про экзотику не будем), и символ "ъ" будет буквой хоть в Испании, хоть в Китае.
Или это глюк маковской стандартной библиотеки?
Здравствуйте, Went, Вы писали:
W>Во-первых, мне не хочется переключать локаль в иную, чем стоит по умолчанию,
Заметь, что когда программа стартует, у неё локаль "C". Это не та локаль, которая стоит у пользователя.
И в локале "C" нет вообще никакой кириллицы или юникода.
Программы, которым хочется использовать пользовательскую не зря вызывают при старте setlocale(LC_ALL, "").
W> Да и при чем тут локаль, строго говоря? Мне просто нужно узнать класс символа, который однозначно определяется этими двумя байтами (про экзотику не будем), и символ "ъ" будет буквой хоть в Испании, хоть в Китае.
Код символа в юникоде — да, не зависит и определяется номером.
Только вот что будет читаться или писаться в поток wcin/wcout определяется локалью.
То есть это разные задачи.
Если нужно определить класс юникод-символа по его же номеру в юникод-таблице, то нужно брать библиотеку для работы с юникодом.
Went:
W>во-вторых, даже с указанием локали "en_US.utf8" русские буквы ей все равно не нравятся
Бросается в глаза, что тут ты указываешь utf8, так где фактически utf16 (или utf32).
По дефолтной локали ничего не могу сказать, не знаю.
Модератор-националист Kerk преследует оппонентов по политическим мотивам.
Здравствуйте, Bill Baklushi, Вы писали: W>>во-вторых, даже с указанием локали "en_US.utf8" русские буквы ей все равно не нравятся BB>Бросается в глаза, что тут ты указываешь utf8, так где фактически utf16 (или utf32). BB>По дефолтной локали ничего не могу сказать, не знаю.
Ну, я скопировал пример с cppreference
Здравствуйте, Went, Вы писали:
W>Не заработало. Во-первых, мне не хочется переключать локаль в иную, чем стоит по умолчанию, во-вторых, даже с указанием локали "en_US.utf8" русские буквы ей все равно не нравятся (я вижу, что там en, но и "ru_RU.utf8" тоже не имеет эффекта). Да и при чем тут локаль, строго говоря? Мне просто нужно узнать класс символа, который однозначно определяется этими двумя байтами (про экзотику не будем), и символ "ъ" будет буквой хоть в Испании, хоть в Китае. W>Или это глюк маковской стандартной библиотеки?
Они все такие — у них другие цели.
По-моему, тебе нужно подключить ICU.
Она популярна, так что будет уже установлена почти наверняка.
Здравствуйте, watchmaker, Вы писали:
W>Заметь, что когда программа стартует, у неё локаль "C". Это не та локаль, которая стоит у пользователя. W>И в локале "C" нет вообще никакой кириллицы или юникода.
Ну, в винде же с локалью по умолчанию iswalnum русские буквы пропускает... То есть это глюк винды? А макось делает все верно?
W>Программы, которым хочется использовать пользовательскую не зря вызывают при старте setlocale(LC_ALL, "").
Этот код установит пользовательскую? Но, все равно, я так понимаю, это мне не поможет? Даже если главный язык стоит русским?
W>То есть это разные задачи. W>Если нужно определить класс юникод-символа по его же номеру в юникод-таблице, то нужно брать библиотеку для работы с юникодом.
То есть iswalnum и прочие подобные функции для моей задачи не годятся? Понятно.
W>https://stackoverflow.com/questions/11107608/whats-wrong-with-c-wchar-t-and-wstrings-what-are-some-alternatives-to-wide/11107667#11107667
Постараюсь разобраться, спасибо
W>В некотором смысле wchar_t сломан везде. Он не подходит для работы с юникодом. Этот тип как раз про локали. W>Нужно использовать ui32 для codepoints, и что-нибудь вроде utf8 для строк (ну или utf16, utf32, где надо).
Это теоретически или практически? В вижуале wchar_t имеет размер в 16бит. Разве этого недостаточно для того, чтобы записать любую реальную букву? Ну, пускай, с небольшими ограничениями? Или есть опасность, что где-то wchar_t будет вообще 8бит?
Здравствуйте, Went, Вы писали:
W>Это теоретически или практически? В вижуале wchar_t имеет размер в 16бит. Разве этого недостаточно для того, чтобы записать любую реальную букву? Ну, пускай, с небольшими ограничениями?
1. "Реальные" помещались в 16 бит до массового наступления эпохи эмодзи в юникоде. С ними, то есть последние лет 5 выход за пределы 0-FFFF это скорее норма, чем исключение.
В пару суррогатов это, конечно, влезет, но уже не столь просто.
2. Вы что имели в виду под "буква"? Цифры уже не в счёт? Символ, если быть точным, с самого начала не влазил — за счёт модификаторов: Á̃̈̌ это одна символ (и таки буква), но пять пунктов UTF-16.
Если считаете это не проблемой — учтите, что, например, софт под всякими макосями любит генерировать Й как Й (в два пункта). И это уже буква. Если U+0418 ещё таким простым iswalnum() будет принят, то идущий за ним U+0306 — уже нет.
W> Или есть опасность, что где-то wchar_t будет вообще 8бит?