Zakresy pisane małymi i dużymi literami alfabetu nie przekraczają %32
granicy „wyrównania” w systemie kodowania ASCII.
Dlatego bit 0x20
jest jedyną różnicą między wersjami tej samej litery z dużych / małych liter.
Gdyby tak nie było, musiałbyś dodawać lub odejmować 0x20
, a nie tylko przełączać, a dla niektórych liter byłoby przeprowadzane, aby przerzucić inne wyższe bity. (I nie byłoby ani jednej operacji, która mogłaby się przełączać, a sprawdzenie znaków alfabetu w pierwszej kolejności byłoby trudniejsze, ponieważ nie można | = 0x20 wymusić lcase.)
Powiązane sztuczki tylko ASCII: możesz sprawdzić alfabetyczny znak ASCII , wymuszając małe litery za pomocą, c |= 0x20
a następnie sprawdzając, czy (bez znaku) c - 'a' <= ('z'-'a')
. Więc tylko 3 operacje: OR + SUB + CMP w porównaniu ze stałą 25. Oczywiście kompilatory wiedzą, jak zoptymalizować (c>='a' && c<='z')
dla Ciebie taki asm , więc co najwyżej powinieneś wykonać tę c|=0x20
część samodzielnie. Raczej niewygodne jest samodzielne wykonywanie wszystkich niezbędnych rzutów, zwłaszcza w celu obejścia domyślnych promocji całkowitych na podpisane 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
Zobacz także Konwertuj ciąg w C ++ na wielkie litery (ciąg SIMD toupper
tylko dla ASCII, maskujący operand dla XOR przy użyciu tego sprawdzenia).
A także jak uzyskać dostęp do tablicy znaków i zmienić małe litery na duże i odwrotnie
(C z elementami wewnętrznymi SIMD i skalarnym odwracaniem wielkości liter x86 asm dla alfabetycznych znaków ASCII, pozostawiając inne niezmodyfikowane).
Te triki są głównie przydatne tylko przy ręcznej optymalizacji przetwarzania tekstu za pomocą SIMD (np. SSE2 lub NEON), po sprawdzeniu, że żaden z char
s w wektorze nie ma ustawionego wysokiego bitu. (A zatem żaden z bajtów nie jest częścią wielobajtowego kodowania UTF-8 dla pojedynczego znaku, który może mieć różne odwrotne wielkie / małe litery). Jeśli znajdziesz, możesz wrócić do wartości skalarnej dla tego fragmentu 16-bajtowego lub dla reszty ciągu.
Istnieją nawet ustawienia narodowe, w których toupper()
lub tolower()
na niektórych znakach z zakresu ASCII tworzą znaki spoza tego zakresu, zwłaszcza tureckie, gdzie I ↔ ı i İ ↔ i. W tych lokalizacjach potrzebowałbyś bardziej wyrafinowanej kontroli lub prawdopodobnie nie próbowałbyś w ogóle używać tej optymalizacji.
Ale w niektórych przypadkach możesz założyć ASCII zamiast UTF-8, np. Narzędzia Unix z LANG=C
(locale POSIX), nie en_CA.UTF-8
lub cokolwiek.
Ale jeśli możesz zweryfikować, że jest to bezpieczne, możesz toupper
znacznie szybciej łańcuchy średniej długości niż wywoływanie toupper()
w pętli (np. 5x), a ostatnio testowałem z Boost 1.58 , znacznie szybciej niż boost::to_upper_copy<char*, std::string>()
robi to głupio dynamic_cast
dla każdej postaci.
@
na `używając^ 32
.