gpt4 book ai didi

go - 如何确定 fmt.Fscanf 消耗的空白数量?

转载 作者:数据小太阳 更新时间:2023-10-29 03:17:54 25 4
gpt4 key购买 nike

我正在尝试在 Go 中实现 PPM 解码器。 PPM 是一种图像格式,由明文 header 和一些二进制图像数据组成。标题看起来像这样(来自 spec ):

Each PPM image consists of the following:

  1. A "magic number" for identifying the file type. A ppm image's magic number is the two characters "P6".
  2. Whitespace (blanks, TABs, CRs, LFs).
  3. A width, formatted as ASCII characters in decimal.
  4. Whitespace.
  5. A height, again in ASCII decimal.
  6. Whitespace.
  7. The maximum color value (Maxval), again in ASCII decimal. Must be less than 65536 and more than zero.
  8. A single whitespace character (usually a newline).

我尝试用 fmt.Fscanf 解码这个 header 功能。下面调用 fmt.Fscanf解析 header (不解决下面解释的警告):

var magic string
var width, height, maxVal uint

fmt.Fscanf(input,"%2s %d %d %d",&magic,&width,&height,&maxVal)

documentationfmt状态:

Note: Fscan etc. can read one character (rune) past the input they return, which means that a loop calling a scan routine may skip some of the input. This is usually a problem only when there is no space between input values. If the reader provided to Fscan implements ReadRune, that method will be used to read characters. If the reader also implements UnreadRune, that method will be used to save the character and successive calls will not lose data. To attach ReadRune and UnreadRune methods to a reader without that capability, use bufio.NewReader.

因为最后一个空格之后的下一个字符已经是图像数据的开头,所以我必须确定有多少个空格 fmt.Fscanf看完有消费MaxVal .我的代码必须在调用者提供的任何读取器上工作,并且它的一部分不能读取超过 header 的末尾,因此将内容包装到缓冲读取器中不是一种选择;缓冲的阅读器可能从输入中读取的内容比我实际想要读取的要多。

一些测试表明在最后解析一个虚拟字符可以解决问题:

var magic string
var width, height, maxVal uint
var dummy byte

fmt.Fscanf(input,"%2s %d %d %d%c",&magic,&width,&height,&maxVal,&dummy)

是否保证按照规范工作?

最佳答案

不,我不认为那是安全的。虽然它现在可以工作,但文档指出该函数保留读取一个字符后的值的权利,除非您有 UnreadRune() 方法。

通过将阅读器包装在 bufio.Reader 中,您可以确保阅读器具有 UnreadRune() 方法。然后您需要自己阅读最后的空格。

buf := bufio.NewReader(input)
fmt.Fscanf(buf,"%2s %d %d %d",&magic,&width,&height,&maxVal)
buf.ReadRune() // remove next rune (the whitespace) from the buffer.


编辑:

正如我们在聊天中讨论的那样,您可以假设虚拟字符方法有效,然后编写测试以便您知道它何时停止工作。测试可以是这样的:

func TestFmtBehavior(t *testing.T) {
// use multireader to prevent r from implementing io.RuneScanner
r := io.MultiReader(bytes.NewReader([]byte("data ")))

n, err := fmt.Fscanf(r, "%s%c", new(string), new(byte))
if n != 2 || err != nil {
t.Error("failed scan", n, err)
}

// the dummy char read 1 extra char past "data".
// one byte should still remain
if n, err := r.Read(make([]byte, 5)); n != 1 {
t.Error("assertion failed", n, err)
}
}

关于go - 如何确定 fmt.Fscanf 消耗的空白数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15841257/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com