如何使用 sscanf 忽略字段(%* 被拒绝)

Posted

技术标签:

【中文标题】如何使用 sscanf 忽略字段(%* 被拒绝)【英文标题】:How to ignore fields with sscanf (%* is rejected) 【发布时间】:2013-04-05 02:40:44 【问题描述】:

我希望在使用 sscanf 处理字符串时忽略特定字段。

sscanf 的手册页说

An optional '*' assignment-suppression character: scanf() reads input as directed by the conversion specification, but discards the input. No corresponding pointer argument is required, and this specification is not included in the count of successful assignments returned by scanf().

尝试在 Golang 中使用它,忽略第三个字段:

if c, err := fmt.Sscanf(str, " %s %d %*d %d ", &iface.Name, &iface.BTx, &iface.BytesRx); err != nil || c != 3 

编译正常,但在运行时 err 设置为:

bad verb %* for integer

Golang doco 没有特别提到 %* 转换规范,但它确实说,

Package fmt implements formatted I/O with functions analogous to C's printf and scanf.

这并不表示 %* 没有实现,所以......我做错了吗?或者它只是被悄悄地忽略了? ...但是,为什么它会编译?

【问题讨论】:

【参考方案1】:

据我所知,这个任务没有这样的动词(因为fmt 包中调用了格式说明符)。但是,您可以做的是指定一些动词并忽略其值。不过,这对内存不是特别友好。理想情况下,这会起作用:

fmt.Scan(&a, _, &b)

很遗憾,事实并非如此。因此,您的下一个最佳选择是声明变量并忽略该变量 你不想要:

var a,b,c int
fmt.Scanf("%d %v %d", &a, &b, &c)
fmt.Println(a,c)

%v 将读取空格分隔的标记。根据您正在扫描的内容,您可以快进 流到您需要扫描的位置。见this answer 有关在缓冲区中查找的详细信息。如果您使用的是 stdio 或者您不知道输入的长度可能 有,你好像运气不好。

这并不表示 %* 没有实现,所以...我在做吗 错误的?或者它只是被悄悄地忽略了? ...但是,为什么会这样 编译?

它可以编译,因为对于编译器来说,格式字符串就像其他字符串一样。该字符串的内容在运行时由fmt 包的函数进行评估。一些 C 编译器可能会检查格式字符串 为正确起见,但这是a feature,不是常态。使用 go,go vet 命令将尝试警告您有关参数不匹配的格式字符串错误。

编辑

对于需要解析一行整数并只处理其中一些整数的特殊情况,您 可以将fmt.Scan 与整数切片结合使用。以下示例读取 3 个整数 来自标准输入并将它们存储在名为 vals 的切片中:

ints := make([]interface, 3)
vals := make([]int, len(ints))

for i, _ := range ints 
    ints[i] = interface(&vals[i])


fmt.Scan(ints...)
fmt.Println(vals)

这可能比传统的 split/trim/strconv 链要短。它制作了一片指针 每个都指向vals 中的一个值。 fmt.Scan 然后填充这些指针。有了这个你甚至可以 通过一遍又一遍地为不需要的值分配相同的指针来忽略大多数值:

ignored := 0

for i, _ := range ints 
    if(i == 0 || i == 2) 
        ints[i] = interface(&vals[i])
     else 
        ints[i] = interface(&ignored)
    

上面的例子会将ignore的地址分配给除第一个和第二个之外的所有值,因此 通过覆盖有效地忽略它们。

【讨论】:

感谢您的回复。我还没有完全跟上。明确说明我的意图 - 我希望丢弃输入的第三个字段。即,禁止转换为参数。您的代码行似乎为将该字段转换为参数提供了宽度精度。 哦,看来我误解了你的问题,我会更新我的答案。 干杯...“做不到”不是我想听到的答案,但它仍然是一个答案!为了便于查看,我的示例已被修剪 - 我实际上正在解析 /proc/net/dev 的输出,并且只对字段 1,2 和 10 感兴趣。我不打算声明 7 个不需要的整数...我有一个使用字符串的多行解决方案。 Split、Fields、Trim 和 strconv.Atoi——在 C 语言中,我会使用单个 sscanf。

以上是关于如何使用 sscanf 忽略字段(%* 被拒绝)的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch:如何在导入时忽略格式错误的数据

在小米 android 11 设备上,我们的 android 应用程序的忽略电池优化权限被拒绝

`tap` 函数如何被忽略?

如何忽略 JSON 响应中列表中的特定字段

表单字段被拒绝,我不知道为啥

74.sscanf数据扫描