【发布时间】:2013-04-05 18:44:53
【问题描述】:
我正在尝试在 Go 中实现 PPM 解码器。 PPM 是一种图像格式,由纯文本标题和一些二进制图像数据组成。标头看起来像这样(来自spec):
每个 PPM 图像包含以下内容:
- 用于识别文件类型的“幻数”。 ppm 图像的幻数是两个字符“P6”。
- 空格(空格、TAB、CR、LF)。
- 宽度,格式为十进制的 ASCII 字符。
- 空白。
- 高度,同样是 ASCII 十进制。
- 空白。
- 最大颜色值 (Maxval),同样以 ASCII 十进制表示。必须小于 65536 且大于零。
- 单个空白字符(通常是换行符)。
我尝试使用fmt.Fscanf 函数解码此标头。以下调用
fmt.Fscanf 解析标题(不解决下面解释的警告):
var magic string
var width, height, maxVal uint
fmt.Fscanf(input,"%2s %d %d %d",&magic,&width,&height,&maxVal)
fmt 的 documentation 声明:
注意:
Fscan等可以在输入后读取一个字符(符文) return,这意味着调用扫描例程的循环可能会跳过一些 的输入。这通常只有在没有空间时才会出现问题 输入值之间。如果读者提供给Fscan实现ReadRune,该方法将用于读取字符。如果读者 还实现了UnreadRune,该方法将用于保存 字符和连续调用不会丢失数据。附上ReadRune和UnreadRune方法给没有这种能力的读者,使用bufio.NewReader.
由于最后一个空格之后的下一个字符已经是图像数据的开头,所以我必须确定在阅读MaxVal 后消耗了多少空格fmt.Fscanf。我的代码必须在调用者提供的任何阅读器上工作,并且它的部分内容不得超过标头的末尾,因此将内容包装到缓冲阅读器中不是一种选择;缓冲阅读器从输入中读取的内容可能比我实际想要阅读的内容更多。
一些测试表明,最后解析一个虚拟字符可以解决问题:
var magic string
var width, height, maxVal uint
var dummy byte
fmt.Fscanf(input,"%2s %d %d %d%c",&magic,&width,&height,&maxVal,&dummy)
这能保证按照规范工作吗?
【问题讨论】:
标签: go scanf off-by-one