前言
字符串处理是编程世界中一项基础技能,特别是对于C/C++的程序员们,远没有那么多华丽的工具可以使用,大多数时候都需要一个个字符来判断和处理,甚至对于C语言来说都没有字符串类型,字符数组是其常见的等价结构,所以稳扎稳打的基本功尤其重要。
对于C++而言,确实有string
这个字符串类型,在使用的时候有一些技巧和函数可以使用,比C语言要方便许多了,只是有些时候我们并不知道可以这样用,有时一些很朴素的写法会让程序更加简洁,而一些技巧的表达当明白之后也会感叹自己曾经的无知。
ASCII 码
作为字符编码的基础,ASCII码是需要先弄明白的,即使不能把所有的ASCII码对应的字符都记住,也要把常见的字母、数字、特殊字符记住,这样在处理字符问题时可以得心应手,常见的ASCII码对照表如下:
其中需要注意的知识点:
- 前32个为非打印控制字符,后面的字符为打印字符
- 数字字符
'0'-'9'
对应的ASCII码范围是48-57 - 大写字母
'A'-'Z'
对应的ASCII码范围是65-90 - 小写字母
'a'-'z'
对应的ASCII码范围是97-122 NULL
对应ASCII码0,回车的ASCII码是13,换行的ASCII码是10
仔细观察这个ASCII表你会发现很多“秘密”,比如 windows 中的文件放到 linux 上打开时常常显示许多的 ^M
,其实这就是\r
的表现,因为在 windows 上用 \r\n
表示换行,而 linux 上使用 \n
换行,那么多余的 \r
在 linux 上就会显示成 ^M
。
再比如小写字母 a
和大写字母 A
中间差了32,为什么不是26呢?为什么要在中间插入几个别的字符,搞成连续的不好吗?之前没想过这个问题,但是前两天看了一个高手的代码后,我大概明白了,这个32的差距应该是一种“炫技”的表现,它可以使得许多代码逻辑变得简单。
判断字符范围的函数
C 语言
C语言中判断的字符范围的函数都在头文件 <ctype.h>
中,常见的有下面这些
int isalnum(int c)
:检查所传的字符是否是字母和数字int isalpha(int c)
:检查所传的字符是否是字母int isdigit(int c)
:检查所传的字符是否是十进制数字int islower(int c)
:检查所传的字符是否是小写字母int isupper(int c)
:检查所传的字符是否是大写字母int ispunct(int c)
:检查所传的字符是否是标点符号字符
C++
C++ 中其实大部分还是引用C语言里的这些函数,但是头文件的名字为 <cctype>
,在C++11中加了一个 int isblank(int c)
函数。
字符判断技巧
判断两个字符互为大小写
看到这个问题第一直觉是什么?很简单的问题有木有?因为知道一个字母的大小写差了32,所以会写出下面的代码:
1 |
|
不过我前两天看到一段代码,它是这样写的:
1 | (x ^ 32) == y; |
看到这里你还以为 A
和 a
之间差32而不是26感到迷惑吗?简单的字符编排透露着巨大的智慧。
哨兵的使用
比如取出一个字符串 string s
中所有的数字,问题很简单,但是结尾字符的处理往往体现了编程的功底,加上一个哨兵字符可以使得编程逻辑简单许多,无须再对结尾字符特殊判断。
1 | void find(string s) { |
总结
'0'
的ASCII码是48,'A'
的ASCII码是65,'a'
的ASCII码是97isdigit
可以判断字符是否是数字,isalpha
可以判断字符是否为字母- 一个字母的大小写对应的ASCII码正好差32,判断互为大小写时可以使用异或符号
(x ^ 32) == y
- 字符串结尾加哨兵字符可以使得处理逻辑更加简单统一,这种编程技巧在其他结构中也常常出现
今天看到一个一直作为榜样的知识输出者宣布财富自由,满心羡慕,是真的羡慕!关键人家比我年轻,比我工作时间还短,已经依靠短短4、5年的努力达到了自由状态,不过了解他的经历会发现他确实付出了很多,而我们大多数作为普通人太安于现状了,有时候选择比努力重要,如果选择对了又付出了加倍的努力,那……
2021-3-28 23:27:32