Ответ 1
В кодировке UTF-8 строка "[一-龠々〆ヵヶ]"
равна этой: "[\xe4\xb8\x80-\xe9\xbe\xa0\xe3\x80\x85\xe3\x80\x86\xe3\x83\xb5\xe3\x83\xb6]"
. И это не класс символов droid, который вы ищете.
Класс символов, который вы ищете, - это тот, который включает в себя:
- любой символ в диапазоне U + 4E00..U + 9FA0; или
- любой из символов 々, 〆, ヵ, ヶ.
Указанный вами класс символов таков:
- любой из "символов" \xe4 или \xb8; или
- любой "символ" в диапазоне \x80..\xe9; или
- любой из "символов" \xbe,\xa0,\xe3,\x80,\x85,\xe3 (снова),\x80 (снова),\x86,\xe3 (снова),\x83,\xb5,\xe3 (снова),\x83 (снова),\xb6.
Неплохо, не так ли? Вы видите проблему?
Это не будет соответствовать "латинским" символам (что, я полагаю, вы имеете в виду такие вещи, как a-z), потому что в UTF-8 все используют один байт ниже 0x80, и ни один из них не находится в этом беспорядочном символьном классе.
Он не будет соответствовать "中"
либо потому, что "中"
имеет три "символа", и ваше регулярное выражение совпадает только с одним "символом" из этого странного длинного списка. Попробуйте assert(std::regex_match("中", std::regex("...")))
, и вы увидите.
Если вы добавили +
, это работает, потому что "中"
имеет три из этих "символов" в вашем странном длинном списке, и теперь ваше регулярное выражение соответствует одному или нескольким.
Если вы добавите {1}
, это не соответствует, потому что мы вернулись к сопоставлению трех "символов" с одним.
Кстати, "中"
соответствует "中"
, потому что мы сопоставляем три "символа" с теми же тремя "символами" в том же порядке.
Что регулярное выражение с +
действительно будет соответствовать некоторым нежелательным вещам, потому что оно не заботится о порядке. Любой символ, который может быть сделан из этого списка байтов в UTF-8, будет соответствовать. Он будет соответствовать "\xe3\x81\x81"
(ぁ U + 3041), и он будет даже соответствовать недопустимому входу UTF-8, например "\xe3\xe3\xe3\xe3"
.
Большая проблема заключается в том, что вы используете библиотеку регулярных выражений, которая даже не поддерживает поддержку уровня 1 для Unicode, минимальный минимум. Он мутит байты и не так много может сделать ваше дорогое крошечное регулярное выражение.
И еще большая проблема заключается в том, что вы используете жестко заданный набор символов для указания "любого японского иероглифа или иероглифа". Почему бы не использовать свойство Unicode Script для этого?
R"(\p{Script=Han})"
О, верно, это не будет работать с регулярными выражениями С++ 11. На мгновение я почти забыл, что это раздражительно хуже, чем бесполезно с Unicode.
Итак, что вы должны делать?
Вы можете декодировать свой ввод в std::u32string
и использовать char32_t
для соответствия. Это не даст вам этого беспорядка, но вы по-прежнему будете иметь диапазоны жесткого кодирования и исключения, если вы имеете в виду "набор символов, которые имеют определенное свойство".
Я рекомендую вам забыть о регулярных выражениях С++ 11 и использовать некоторую библиотеку регулярных выражений с минимальной поддержкой Unicode уровня 1, например, в ICU.