5

我希望在使用 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.

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

4

1 回答 1

4

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

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

可悲的是,它没有。因此,您的下一个最佳选择是声明变量并忽略您不想要的变量:

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

%v将读取一个空格分隔的标记。根据您正在扫描的内容,您可以将流快进到您需要扫描的位置。有关在缓冲区中查找的详细信息,请参阅此答案 。如果您使用的是 stdio 或者您不知道您的输入可能有多长,那么您在这里似乎不走运。

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

它可以编译,因为对于编译器来说,格式字符串就像其他字符串一样。该字符串的内容在运行时由fmt包的函数进行评估。一些 C 编译器可能会检查格式字符串的正确性,但这是一个特性,而不是规范。使用 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除第一个和第二个之外的所有值,从而通过覆盖有效地忽略它们。

于 2013-04-05T02:57:50.617 回答