编程小技巧

    返回首页    发表留言
本文作者:李德强
          技巧十三:大小写转换
 
 

        今天跟大家分享的小技巧是关于英文字母的大小写转换的。有时候我们会遇到一些关于字母大小写转换的问题,比如将某一个字符串中的字母转为大写,或转为小写,将Hello World转为HELLO WORLD或是转为hello world。那么我们需要如何来设计程序呢?说到大小写转换,我们自然就想到了将'a'转为'A';将'b'转为'B';将'c'转为'C'……也就是说我们可以遍历字符串中所有的字符,并判断当前字符是'a'、'b'、'c'……的哪一个,然后再把它们转为对应的大写字母'A'、'B'、'C'……具体的程序如下:

char toUpperCase(char ch)
{
        if (ch == 'a')
        {
                return 'A';
        }   
        if (ch == 'b')
        {
                return 'B';
        }   
        if (ch == 'c')
        {
                return 'C';
        }  
 
        ......

        if (ch == 'z') 
        { 
                return 'Z'; 
        } 
        return ch;
}

        我们来这样编写程序从结果上看没有任何问题,但这段程序的运行效率实在太低了,而且26个字母就需要编写26个判断条件,这样的程序过于笨拙。我们换一个角度思考这个问题,先来回顾一下英文字母在ASCII码表中的编码和位置:

二进制 十进制 十六进制 图形
0100 0001 65 41 A
0100 0010 66 42 B
0100 0011 67 43 C
0100 0100 68 44 D
0100 0101 69 45 E
0100 0110 70 46 F
0100 0111 71 47 G
0100 1000 72 48 H
0100 1001 73 49 I
0100 1010 74 4A J
0100 1011 75 4B K
0100 1100 76 4C L
0100 1101 77 4D M
0100 1110 78 4E N
0100 1111 79 4F O
0101 0000 80 50 P
0101 0001 81 51 Q
0101 0010 82 52 R
0101 0011 83 53 S
0101 0100 84 54 T
0101 0101 85 55 U
0101 0110 86 56 V
0101 0111 87 57 W
0101 1000 88 58 X
0101 1001 89 59 Y
0101 1010 90 5A Z
 
二进制 十进制 十六进制 图形
0110 0001 97 61 a
0110 0010 98 62 b
0110 0011 99 63 c
0110 0100 100 64 d
0110 0101 101 65 e
0110 0110 102 66 f
0110 0111 103 67 g
0110 1000 104 68 h
0110 1001 105 69 i
0110 1010 106 6A j
0110 1011 107 6B k
0110 1100 108 6C l
0110 1101 109 6D m
0110 1110 110 6E n
0110 1111 111 6F o
0111 0000 112 70 p
0111 0001 113 71 q
0111 0010 114 72 r
0111 0011 115 73 s
0111 0100 116 74 t
0111 0101 117 75 u
0111 0110 118 76 v
0111 0111 119 77 w
0111 1000 120 78 x
0111 1001 121 79 y
0111 1010 122 7A z

        我们注意到A-Z和a-z这些字母都是按顺序编码的,并且同一个字母的大小写编号都差32,也就是说'a'-'A' == 32;'b'-'B' == 32;'c'-'C' == 32; ... 'z'-'Z' == 32。当我们看到这个规律时,大小写转换的问题就变的简单明了了:

  • 小写字母转换为大写字母,只需要将其编码减去32即可;
  • 大写字母转换为小写字母,只需要将其编码加上32即可。

        于是我们的程序就可以这样来编写:

void toUpperCase(char *p) 
{
        while (*p != '\0')
        {   
                if (*p >= 'a' && *p <= 'z')
                {   
                        *p -= 32; 
                }
        }   
}

        上面程序是将字符串中的小写字母转为大写字母,对于大写转小写的情况只需要将条件判断处修改成A到Z并将*p -= 32;这里的减号修改成加号修改*p += 32;即可。

        这样的程序就比较美观并且高效了,但还有没有更好的办法来解决这个问题呢?我们继续来观察ASCII码表中的编码,可以看到任意一个字母的大写字符和小字符的二进制编码中只有第5个bit位(从右向左依次为第0位、第1位、第2位、第3位、第4位、第5位、第6位、第7位)不同,其它bit位上的数值都是相同的,例如:

0100 0001    A        0110 0001    a
0100 0010    B        0110 0010    b
0100 0011    C        0110 0011    c

       也就是说所有大写字母的第5个bit位上都是0,而所有小写字母的第5个bit位上都是1(当初American National Standard Institute制定ASCII码时就是这样巧妙的设计),所以:

  • 将一个字母转为小写,只需要将其第5个bit位转为1即可;
  • 将一个字母转为大写,只需要将其第5个bit位转为0即可。

        于是我们的程序就可以这样来编写:

char toUpperCase(char *p)
{
        while (*p != '\0')
        {
                if (*p >= 'a' && *p <= 'z')
                {
                        *p &= 0xdf;
                }
        }
}

        上面程序是将字符串中的小写字母转为大写字母,对于大写转小写的情况只需要将条件判断处修改成A到Z并将*p &= 0xdf;这里修改成*p |= 0x20;即可。

        但是这样的程序看起来还是有一点奇怪:0xdf和0x20不是那么人性化,读起来也不是很好懂,我们可以将其修改为以下形式:

//小写转大写
if (*p >= 'a' && *p <= 'z')
{
        //第5个bit位变为0
        *p &= ~(1 << 5);
}

//大写转小写
if (*p >= 'A' && *p <= 'Z')
{
        //第5个bit位变为1
        *p |= (1 << 5);
}

  

        今天的小技巧你学会了吗?

 

    返回首页    返回顶部
#1楼  点苍双剑  于 2017年08月01日09:27:02 发表
 
啊,原来如此,我说65和97相差32,这个32怎么感觉如此的亲切,原来是2的5次方啊。
  看不清?点击刷新

 

  Copyright © 2015-2023 问渠网 辽ICP备15013245号