2023-09-01
经验总结
00
请注意,本文编写于 466 天前,最后修改于 209 天前,其中某些信息可能已经过时。

目录

前言
集合用法
指定字符
范围读取
反向匹配
直到指定字符
抛弃不需要读取的字符
限定读入长度
不赋值符号

Last Edit: 2023/9/1

前言

大家都知道 scanf 中可以以 %d %s %f 等作为占位符,但是有一种特殊的占位符 TA 的形式如: %[<Fmt>],下面称之为 集合占位符

这是一种不大常用的方法,但是个人觉得很好用!

在这里有所提及:CppReference std::scanf,std::fscanf,std::sscanf

下面使用 scanf 来代指和 scanf 有类似功能的函数 ( scanf/sscanf/fscanf等 )

大家可能听说过在字符串匹配操作中有一种常用操作叫正则。集合占位符的用法很类似正则。虽然 STL 中引入了正则库,但在算法竞赛中这个库常常是不被提供的,而集合占位符存在于 C 库中,于是我们可以很方便的使用 TA 来方便地编写字符串处理逻辑。

在上述占位符中的 <Fmt> 需要填入一些用于控制格式的字符,这会在下面简单地讲述并给出例子,具体建议参照 Cppreference 上的表格来了解。

集合用法

指定字符

某些时候,题目中会有用于标识类型的字符(e.g. 操作一以字符 'a' 开头, 操作二以字符 'b' 开头),我们就可以愉快地使用集合占位符了。

e.g.: 想要读取 #+?$ 这四种字符中的任意一种 ( Luogu P2814 家谱 ),那么我们可以这样:

cpp
char c; scanf("%[#+?$]", &c);

在运行过程中,只有遇到 #+?$ 中任意一个字符才会对变量 c 进行赋值操作,会给变量 c 赋值上上述提到的任一读到的字符,否则 scanf 将一直按位从 stdin 读取字符、直到遇到规定的字符或结束操作。

有一种特殊情况需要考虑,[] 显然也是 ASCII 字符。如果使用类似 %[]] 的占位符,会按照指定 ] 字符进行读取。

范围读取

有些时候,我们可能会遇到需要读取数字/字母的情况。

这里介绍的使用方法,可以读取一个字符区间内的字符。

有的人就会问了:我干嘛不写个快读? 反问:就用一次你写啥快读?写炸了咋办?

e.g.: 想要读取一个字符的数字字符,那么我们可以这样:

cpp
char c; scanf("%[0-9]", &c);

那还想读一下多位的数字怎么办,看这里:

cpp
char c[50]; scanf("%[0-9]", c);

你还记得上面使用指定字符的时候,我们可以同时放入多个字符吗?有没有一种可能,在范围读取的时候也可以这么做,下面给出常用情况的例子:

  • %[A-Za-z] 匹配所有的英语字母
  • %[A-Za-z0-9] 匹配所有的英文字母和十进制数字
  • %[a-f0-9] 匹配十六进制数字(注意,只能读入字符串。如果你希望读入,请使用 %x

反向匹配

我们可以使用 ^ 符号开头的限定符来规定直到哪个/哪些字符我们才停止读入,这样一来就可以读取到指定字符或抛弃不需要读取的字符了!

直到指定字符

e.g.: 我们想读取到 \n 字符才结束,可以这样

cpp
char l[50]; scanf("%[^\n]", l);

在这种情况,遇到了 \n 字符的时候会直接结束,所以字符串 l 的最后一位不是 \n

但在输入流里面还有一个 \n 字符,这时候我们最好这么写

cpp
char l[50]; scanf("%[^\n] ", l);

相比于上一段代码多了个空格,这意味着清理掉输入流中的空白字符。

抛弃不需要读取的字符
cpp
scanf("%*[^\n] ");

这样我们就可以直接抛弃掉一行输入(但好像不多用)。

限定读入长度

很多时候我们需要限定读入字符的数量,这也可以通过某些方法来实现。

e.g.: stdin 为 123456 的情况下,使用如下代码,输出为 123

cpp
char buf[50]; scanf("%3[0-9]", buf); printf("%s", buf);

当然,不只是集合占位符才可以这样用,这同样适用于 %s 之类的占位符。

不赋值符号

正常情况 scanf 需要在参数中提供一个指针来进行赋值

但总有一些时候我们希望不这么做,e.g. 去除一些无效的字符时。

如果你只是想忽略特定格式的字符串,在 %s 等占位符中,可以使用 * 来表明这个占位符不需要赋值

显然,集合占位符也可以使用抑制赋值标志 *

e.g.:

  1. 清空一个到 \n 的字符串,那么我可以这么用:
    cpp
    scanf("%*[^\n]");
  2. 清空一个由小写字母组成的字符串,那么我可以这么写:
    cpp
    scanf("%*[a-z]");

本文作者:CornWorld

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!