Rentang alfabet huruf kecil dan huruf besar tidak melewati batas %32
"alignment" dalam sistem pengkodean ASCII.
Inilah sebabnya mengapa bit 0x20
adalah satu-satunya perbedaan antara versi huruf besar / kecil dari huruf yang sama.
Jika ini bukan masalahnya, Anda harus menambah atau mengurangi 0x20
, bukan hanya beralih, dan untuk beberapa huruf akan ada tugas untuk membalik bit lain yang lebih tinggi. (Dan tidak akan ada satu operasi yang bisa beralih, dan memeriksa karakter alfabet di tempat pertama akan lebih sulit karena Anda tidak bisa | = 0x20 untuk memaksa lcase.)
Trik khusus ASCII terkait: Anda dapat memeriksa karakter ASCII alfabet dengan memaksa huruf kecil dengan c |= 0x20
dan kemudian memeriksa apakah (tidak ditandatangani) c - 'a' <= ('z'-'a')
. Jadi hanya 3 operasi: ATAU + SUB + CMP terhadap konstan 25. Tentu saja, kompiler tahu bagaimana mengoptimalkan (c>='a' && c<='z')
ke asm seperti ini untuk Anda , jadi paling-paling Anda harus melakukan c|=0x20
bagian sendiri. Agak merepotkan untuk melakukan sendiri semua pengecoran yang diperlukan, terutama untuk mengerjakan promosi bilangan bulat default yang akan ditandatangani 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
Lihat juga Konversi String Dalam C ++ Ke Huruf Besar (string SIMD toupper
hanya untuk ASCII, menutupi operand untuk XOR menggunakan centang itu.)
Dan juga Cara mengakses array char dan mengubah huruf kecil ke huruf besar, dan sebaliknya
(C dengan SIMD intrinsik, dan skalar x86 asm case-flip untuk karakter ASCII alfabet, membuat yang lain tidak dimodifikasi.)
Trik-trik ini sebagian besar hanya berguna jika tangan mengoptimalkan beberapa pemrosesan teks dengan SIMD (misalnya SSE2 atau NEON), setelah memeriksa bahwa tidak ada char
dalam vektor memiliki bit set tinggi. (Dan dengan demikian tidak ada byte yang merupakan bagian dari multi-byte UTF-8 encoding untuk satu karakter, yang mungkin memiliki invers huruf besar / kecil yang berbeda). Jika Anda menemukannya, Anda dapat kembali ke skalar untuk potongan 16 byte ini, atau untuk sisa string.
Bahkan ada beberapa lokal tempat toupper()
atau tolower()
pada beberapa karakter dalam rentang ASCII menghasilkan karakter di luar rentang itu, terutama Turki di mana saya ↔ ı dan İ ↔ i. Di lokasi tersebut, Anda memerlukan pemeriksaan yang lebih canggih, atau mungkin tidak mencoba menggunakan pengoptimalan ini sama sekali.
Tetapi dalam beberapa kasus, Anda diizinkan untuk menggunakan ASCII alih-alih UTF-8, mis. Utilitas Unix with LANG=C
(the POSIX locale), bukan en_CA.UTF-8
atau apa pun.
Tetapi jika Anda bisa memastikan keamanannya, Anda dapat membuat toupper
string berukuran sedang jauh lebih cepat daripada menelepon toupper()
dalam satu lingkaran (seperti 5x), dan terakhir saya uji dengan Boost 1.58 , jauh lebih cepat daripada boost::to_upper_copy<char*, std::string>()
yang dilakukan bodoh dynamic_cast
untuk setiap karakter.
@
menjadi `dengan menggunakan^ 32
.