Буквенные диапазоны в нижнем и верхнем регистре не пересекают границу %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
s в векторе не установлен старший бит. (И, таким образом, ни один из байтов не является частью многобайтовой кодировки 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
для каждого символа.
@
в `с помощью^ 32
.