go - How to be definite about the number of whitespace fmt.Fscanf consumes? -
i trying implement ppm decoder in go. ppm image format consists of plaintext header , binary image data. header looks (from spec):
each ppm image consists of following:
- a "magic number" identifying file type. ppm image's magic number 2 characters "p6".
- whitespace (blanks, tabs, crs, lfs).
- a width, formatted ascii characters in decimal.
- whitespace.
- a height, again in ascii decimal.
- whitespace.
- the maximum color value (maxval), again in ascii decimal. must less 65536 , more zero.
- a single whitespace character (usually newline).
i try decode header fmt.fscanf
function. following call fmt.fscanf
parses header (not addressing caveat explained below):
var magic string var width, height, maxval uint fmt.fscanf(input,"%2s %d %d %d",&magic,&width,&height,&maxval)
the documentation of fmt
states:
note:
fscan
etc. can read 1 character (rune) past input return, means loop calling scan routine may skip of input. problem when there no space between input values. if reader providedfscan
implementsreadrune
, method used read characters. if reader implementsunreadrune
, method used save character , successive calls not lose data. attachreadrune
,unreadrune
methods reader without capability, usebufio.newreader
.
as next character after final whitespace beginning of image data, have how many whitespace fmt.fscanf
did consume after reading maxval
. code must work on whatever reader provided caller , parts of must not read past end of header, therefore wrapping stuff buffered reader not option; buffered reader might read more input want read.
some testing suggests parsing dummy character @ end solves issues:
var magic string var width, height, maxval uint var dummy byte fmt.fscanf(input,"%2s %d %d %d%c",&magic,&width,&height,&maxval,&dummy)
is guaranteed work according specification?
no, not consider safe. while works now, documentation states function reserves right read past value 1 character unless have unreadrune()
method.
by wrapping reader in bufio.reader
, can ensure reader has unreadrune()
method. need read final whitespace yourself.
buf := bufio.newreader(input) fmt.fscanf(buf,"%2s %d %d %d",&magic,&width,&height,&maxval) buf.readrune() // remove next rune (the whitespace) buffer.
edit:
as discussed in chat, can assume dummy char method works , write test know when stops working. test can like:
func testfmtbehavior(t *testing.t) { // use multireader prevent r 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) } // dummy char read 1 char past "data". // 1 byte should still remain if n, err := r.read(make([]byte, 5)); n != 1 { t.error("assertion failed", n, err) } }
Comments
Post a Comment