转换成小写字母-ASCII码
来源:力扣(LeetCode)[题源链接]
题目:给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。
示例 :
输入:s = “Hello”
输出:“hello”
我们先提前预知一下,ASCII码大写字母转小写字母可以用或与 |=32来转化,后面会解释。
小白尝试1(不通过):
char* toLowerCase(char* s) {
int len = strlen(s);
for(int i=0;i<len;i++)
{
*s |= 32;
s++;
}
return s;
}
*s |= 32;
这行代码只能让s字符串的第一个字符大小写转化
s++
s++,是自加sizeof(s)的大小,执行完s++之后,指向的是s所占大小的下一个字节,而不是s的下一个字符,所以不能直接s++来修改下一个字符
尝试2(通过):
char* toLowerCase(char* s) {
int len = strlen(s);
char *p = s;
for(int i=0;i<len;i++)
{
*p |= 32;
p++;
}
return s;
}
char *p = s;
定义了一个char类型指针*p指向s字符串的地址s
p++
自加一个char类型大小,每次自加后依次指向下一个字符的地址
不另外定义一个指针也可以,用数组来表示
尝试3(通过):
char* toLowerCase(char* s) {
int len = strlen(s);
for(int i=0;i<len;i++)
{
s[i] |= 32;
}
return s;
}
或是用语言的API
官方解答:
char * toLowerCase(char * s){
int len = strlen(s);
for (int i = 0; i < len; ++i) {
s[i] = tolower(s[i]);
}
return s;
}
ASCII字母位运算技巧
在ASCII码中,A-Z对应65-90(十进制),a-z对应97-122,其大小写之间刚好相差32,即相差10 0000(二进制)
手推一下A、Z、a、z的二进制,可以发现因为刚好相差32,他们大小写之间的(二进制),只有第六位是0和1的差别!
运行以下代码
#include <stdio.h>
int main() {
char string[] = "ABCabc";
string[0] += 32;
string[1] |= 32;
string[2] ^= 32;
string[3] -= 32;
string[4] &= -33;
string[5] ^= 32;
for(int i=0; i<6; i++)
printf("%c",string[i]);
return 0;
}
输出打印结果为
abcABC
经过推理,可以得知
大写变小写、小写变大写:字符 ^= 32
大写变小写、小写变小写:字符 |= 32
大写变大写、小写变大写:字符 &= -33
关于&=-33
,涉及到补码,其二进制同~32
只有26字母,为什么大小之间的ASCII差值是32,而不是26?
转载于力扣@疯子 跳转链接
因为字母大小之间的切换是一个很高频的行为,在设计ASCII表时,出于效率的考量,把大小之间的转换需要的 算力 压缩到最小。(关健词:算力)
也就是只需要对一个bit位操作就可以实现大小写之间的切换。
如何压缩算力
如:
int n = 0b100;
n ^= 0b011;
n 最终等于 0b111。虽然只进行了一次 异或 操作,但是对于最底层的 异或 逻辑,是需要对各个bit分别进行一次 异或运算 最终把 3次 的异或累加返回。
同样的逻辑,对应到字母大小之间的切换,每次只需要 1次位操作 就可以得做到大小写切换。(关键词:1次)
从而把大小之间转换的代价压缩到最小。
是的,ASCII里面的字母序是经过细心设计出来的。