abcdefgh↙ abcd
输入示例 ②:
baccbaxyz↙ baccba
使用连接符
为了简化字符集合的写法,scanf() 支持使用连字符-来表示一个范围内的字符,例如 %[a-z]、%[0-9] 等。
连字符左边的字符对应一个 ASCII 码,连字符右边的字符也对应一个 ASCII 码,位于这两个 ASCII 码范围以内的字符就是要读取的字符。注意,连字符左边的 ASCII 码要小于右边的,如果反过来,那么它的行为是未定义的。
常用的连字符举例:
%[a-z]表示读取 abc...xyz 范围内的字符,也即小写字母; %[A-Z]表示读取 ABC...XYZ 范围内的字符,也即大写字母; %[0-9]表示读取 012...789 范围内的字符,也即十进制数字。
你也可以将它们合并起来,例如:
%[a-zA-Z]表示读取大写字母和小写字母,也即所有英文字母; %[a-z-A-Z0-9]表示读取所有的英文字母和十进制数字; %[0-9a-f]表示读取十六进制数字。
请看下面的演示:
#include <stdio.h> int main(){ char str[30]; scanf("%[a-zA-Z]", str); //只读取字母 printf("%s\n", str); return 0; }
输入示例:
abcXYZ123↙ abcXYZ
不匹配某些字符
假如现在有一种需求,就是读取换行符以外的所有字符,或者读取 0~9 以外的所有字符,该怎么实现呢?总不能把剩下的字符都罗列出来吧,一是麻烦,二是不现实。
C语言的开发者们早就考虑到这个问题了,scanf() 允许我们在%[ ]中直接指定某些不能匹配的字符,具体方法就是在不匹配的字符前面加上^,例如:
%[^\n]表示匹配除换行符以外的所有字符,遇到换行符就停止读取; %[^0-9]表示匹配除十进制数字以外的所有字符,遇到十进制数字就停止读取。
请看下面的例子:
#include <stdio.h> int main(){ char str1[30], str2[30]; scanf("%[^0-9]", str1); scanf("%*[^\n]"); scanf("%*c"); //清空缓冲区 scanf("%[^\n]", str2); printf("str1=%s \nstr2=%s\n", str1, str2); return 0; }
输入示例:
abcXYZ@#87edf↙ c c++ java python go javascript↙ str1=abcXYZ@# str2=c c++ java python go javascript
请注意第 6 行代码,它的作用是读取一行字符串,和 gets() 的功能一模一样。你看,scanf() 也能读取带空格的字符串呀,谁说 scanf() 不能完全取代 gets(),这明显是错误的说法。
另外,scanf() 还可以指定字符串的最大长度,指定字符串中不能包含哪些字符,这是 gets() 不具备的功能。
例如,读取一行不能包含十进制数字的字符串,并且长度不能超过 30:
#include <stdio.h> int main(){ char str[31]; scanf("%30[^0-9\n]", str); printf("str=%s\n", str); return 0; }
输入示例 ①:
http://c.biancheng.net http://biancheng.net↙ str=http://c.biancheng.net http://
输入示例 ②:
I have been programming for 8 years.↙ str=I have been programming for
3) 丢弃读取到的字符
在前面的代码中,每个格式控制符都要对应一个变量,把读取到的数据放入对应的变量中。其实你也可以不这样做,scanf() 允许把读取到的数据直接丢弃,不往变量中存放,具体方法就是在 % 后面加一个*,例如:
%*d表示读取一个整数并丢弃; %*[a-z]表示读取小写字母并丢弃; %*[^\n]表示将换行符以外的字符全部丢弃。
请看下面的代码演示: