Буквенные диапазоны в нижнем и верхнем регистре не пересекают границу «выравнивания» %32
в системе кодирования ASCII.
Именно поэтому бит 0x20
единственное различие между версиями одной и той же буквы в верхнем / нижнем регистре.
Если бы это было не так, вам нужно было бы добавить или вычесть 0x20
, а не просто переключить, а для некоторых буквбыло бы проведение, чтобы перевернуть другие старшие биты.(И не было бы ни одной операции, которая могла бы переключаться, и проверка буквенных символов в первую очередь была бы более сложной, потому что вы не можете | = 0x20 заставить lcase.)
Связанный ASCIIтолько трюки: вы можете проверить наличие буквенного символа ASCII , введя строчные буквы с помощью c |= 0x20
и проверив, если (без знака) c - 'a' <= ('z'-'a')
.Так что всего 3 операции: ИЛИ + SUB + CMP против постоянной 25. Конечно, компиляторы знают, как оптимизировать (c>='a' && c<='z')
в asm, подобный этому для вас , так что самое большее вы должнысделай c|=0x20
часть себя.Довольно неудобно выполнять все необходимые кастинги самостоятельно, особенно для обхода целочисленных повышений по умолчанию до подписанных int
.
unsigned char lcase = y|0x20;
if (lcase - 'a' <= (unsigned)('z'-'a')) { // lcase-'a' will wrap for characters below 'a'
// c is alphabetic ASCII
}
// else it's not
См. Также Преобразование строки в C ++ в верхний регистр (SIMD строка toupper
только для ASCII, маскирующая операнд для XOR с помощью этой проверки.)
А также Как получить доступ к массиву символов и изменить строчные буквы на прописные, и наоборот (C со встроенными SIMD и скалярный x86 asm case-flip для буквенных символов ASCII, оставляя другие без изменений.)
Эти приемы в основном полезны только при ручной оптимизации какой-либо обработки текста с помощью SIMD (например, SSE2 или NEON), после проверки того, что ни у одного из char
в векторе не установлен их старший бит.(И, таким образом, ни один из байтов не является частью многобайтовой кодировки UTF-8 для одного символа, который может иметь разные обратные символы верхнего / нижнего регистра).Если вы найдете что-нибудь, вы можете вернуться к скаляру для этого фрагмента из 16 байтов или для остальной части строки.
Есть даже некоторые локали, где toupper()
или tolower()
в некоторыхсимволы в диапазоне ASCII производят символы вне этого диапазона, особенно турецкие, где I ↔ ı и İ ↔ i. В этих локалях вам понадобится более сложная проверка или, возможно, вообще не пытаетесь использовать эту оптимизацию.
Но в некоторых случаях вам разрешено использовать ASCII вместо UTF-8, например, утилиты Unix с LANG=C
(локаль POSIX), а не en_CA.UTF-8
или чем-то еще.
Но если вы можете проверить, что это безопасно, вы можете toupper
строки средней длины гораздо быстрее, чем вызывать toupper()
в цикле (например, 5x), и в последний раз, когда я тестировал Boost 1.58 , намного намного быстрее, чем boost::to_upper_copy<char*, std::string>()
, что делает глупость dynamic_cast
для каждого символа.