Linux 中的小小编程技巧(一) 字符类别判断

本文介绍Linux中高效的字符类别判断方法,通过预设的字符属性数组实现快速判断,如大小写字母、数字等,并提供示例代码。

Linux 中的小小编程技巧(一) 字符类别判断

做驱动开发已经有一段时间了,每日只是关注内核及驱动方面的一些内容,很少查看诸如string.c等类文件的内容。某日看了些这些代码后,颇有感触,感叹其设计方法和技巧,遂做下笔记,留着学习。

今天要说的是lib/ctype.c和include/linux/ctype.h两个文件内的部分内容,内容时关于如何判断一个字符是何种类 型的,比如是否为控制字符,是否为大写,是否为写等。

一般初学情况下判断一个字符为大写的方法用if 语句来判断,比如

If (c>=’A’&&c<=’Z’) return true;

小写的方法与之类似

因为字符A-Z,a-z在ASCII上是连续的,所以一个范围判断就可以了,假设某些字符在ASCII上是不连续的,比如十六进制数,0-9,A-H,那么if语句里面就需要两个范围判断了

If((c>=’0’&&c<=’9’)||(c>=’A’&&c<=’H’)) return true;

再者假设有更多的范围,那么if的条件部分就越长,判断条件长了,效率自然就低了。

    Linux中使用空间换时间的方法来做,基本方法为:

建立一个256个元素的unsigned char _ctypes[]全局数组,每一个数组元素的值代表其下标所对应的ASCII码的类别,比如大写字母A,其ASCII码为65,那么_ctypes[65]中的8个位代表了其所属类别,8个位最多有8中并列的属性。

在Linux中定义了8种属性,其宏为:

  #define _U      0x01   /* upper */

  #define_L      0x02    /* lower */

  #define_D      0x04    /* digit */

  #define_C      0x08    /* cntrl */

  #define_P      0x10    /* punct */

  #define_S      0x20    /* white space (space/lf/tab) */

  #define_X      0x40    /* hex digit */

  #define_SP     0x80    /* hard space (0x20) */ 

Linux中将_ctypes初始化为:

const unsigned char _ctype[]= {

 _C,_C,_C,_C,_C,_C,_C,_C,                                /* 0-7 */

 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,                 /* 8-15 */

 _C,_C,_C,_C,_C,_C,_C,_C,                                /* 16-23 */

 _C,_C,_C,_C,_C,_C,_C,_C,                                /* 24-31 */

 _S|_SP,_P,_P,_P,_P,_P,_P,_P,                            /* 32-39 */

 _P,_P,_P,_P,_P,_P,_P,_P,                                /* 40-47 */

 _D,_D,_D,_D,_D,_D,_D,_D,                                /* 48-55 */

 _D,_D,_P,_P,_P,_P,_P,_P,                                /* 56-63 */

 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,              /* 64-71 */

 _U,_U,_U,_U,_U,_U,_U,_U,                                /* 72-79 */

 _U,_U,_U,_U,_U,_U,_U,_U,                                /* 80-87 */

 _U,_U,_U,_P,_P,_P,_P,_P,                                /* 88-95 */

 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,              /* 96-103 */

 _L,_L,_L,_L,_L,_L,_L,_L,                                /* 104-111 */

 _L,_L,_L,_L,_L,_L,_L,_L,                                /* 112-119 */

 _L,_L,_L,_P,_P,_P,_P,_C,                                /* 120-127 */

 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                        /* 128-143 */

 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                        /* 144-159 */

 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,    /* 160-175 */

 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,        /* 176-191 */

 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,        /* 192-207 */

 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,        /* 208-223 */

 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,        /* 224-239 */

 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};       /* 240-255 */

然后Linux定义了一个宏:

#define __ismask(x)(_ctype[(int)(unsigned char)(x)])

此宏获得一个字符所对应数组中的标志值,

Linux中又定义了一些宏用以辅助判断一个字符类别:

#define isalnum(c)      ((__ismask(c)&(_U|_L|_D)) != 0)       //大写,小写,数字
#define isalpha(c)      ((__ismask(c)&(_U|_L)) != 0)          //大写,小写
#define iscntrl(c)      ((__ismask(c)&(_C)) != 0)             //控制
#define isdigit(c)      ((__ismask(c)&(_D)) != 0)             //数字
#define isgraph(c)      ((__ismask(c)&(_P|_U|_L|_D)) != 0)    //字符是否图形
#define islower(c)      ((__ismask(c)&(_L)) != 0)             //是否小写   
#define isprint(c)      ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)//是否可打印
#define ispunct(c)      ((__ismask(c)&(_P)) != 0)             /* punct */
/* Note: isspace() must return false for %NUL-terminator */
#define isspace(c)      ((__ismask(c)&(_S)) != 0)             /*(space/lf/tab) */
#define isupper(c)      ((__ismask(c)&(_U)) != 0)             //是否大写
#define isxdigit(c)     ((__ismask(c)&(_D|_X)) != 0)          //是否十六进制数
#define isascii(c) (((unsigned char)(c))<=0x7f)               //是否ASCII
#define toascii(c) (((unsigned char)(c))&0x7f)                //转为ASCII

上述宏在程序中可以直接使用了,比如想判断某个字符是否为大写

If (isupper(‘A’)) return true;

If (isxdigit(‘B’)) return true;


比如:

static inline unsigned char __tolower(unsigned char c)//转为小写字母
 {
          if (isupper(c))
                  c -= 'A'-'a';
         return c;
  }
 static inline unsigned char __toupper(unsigned char c)//转为大写字母
 {
         if (islower(c))
                 c -= 'a'-'A';
         return c;
 }


Linux中方法已经描述完了,下面对比优劣。

  普通方法:

      优势:简单易懂,不额外占用数据空间

      劣势:效率较第二种低,需要很多条件判断指令

  Linux方法:

      优势:速度快,一次性位操作即可完成任务,优雅。

      劣势:额外的占用了空间。

    综合:

        如果自己随便写个小小程序的话,第一种方法够用了。如果是一个真实的项目的,推荐第二种方法。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值