What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?

前端 未结 10 1796
孤城傲影
孤城傲影 2020-11-28 03:02

I was solving some problem on codeforces. Normally I first check if the character is upper or lower English letter then subtract or add 32 to convert it to the

10条回答
  •  栀梦
    栀梦 (楼主)
    2020-11-28 03:41

    This uses the fact than ASCII values have been chosen by really smart people.

    foo ^= 32;
    

    This flips the 6th lowest bit1 of foo (the uppercase flag of ASCII sort of), transforming an ASCII upper case to a lower case and vice-versa.

    +---+------------+------------+
    |   | Upper case | Lower case |  32 is 00100000
    +---+------------+------------+
    | A | 01000001   | 01100001   |
    | B | 01000010   | 01100010   |
    |            ...              |
    | Z | 01011010   | 01111010   |
    +---+------------+------------+
    

    Example

    'A' ^ 32
    
        01000001 'A'
    XOR 00100000 32
    ------------
        01100001 'a'
    

    And by property of XOR, 'a' ^ 32 == 'A'.

    Notice

    C++ is not required to use ASCII to represent characters. Another variant is EBCDIC. This trick only works on ASCII platforms. A more portable solution would be to use std::tolower and std::toupper, with the offered bonus to be locale-aware (it does not automagically solve all your problems though, see comments):

    bool case_incensitive_equal(char lhs, char rhs)
    {
        return std::tolower(lhs, std::locale{}) == std::tolower(rhs, std::locale{}); // std::locale{} optional, enable locale-awarness
    }
    
    assert(case_incensitive_equal('A', 'a'));
    

    1) As 32 is 1 << 5 (2 to the power 5), it flips the 6th bit (counting from 1).

提交回复
热议问题