go-ruby-scanf

Ruby's scanf β€” the inverse of sprintf β€” in pure Go, MRI-compatible, no cgo.

pure Go Β· zero cgo scanf grammar Scan / ScanAll %d %i %x %o %a %e %f %g %s %c %[…] widths Β· %* big.Int overflow MRI byte-exact 100% coverage 6 arches
Documentation GitHub
Documentation (MkDocs Material + mike) License: BSD-3-Clause Go 1.26.4+ Coverage 100%

go-ruby-scanf is a pure-Go (no cgo) reimplementation of Ruby's scanf stdlib β€” the deterministic, interpreter-independent core of MRI's String#scanf / IO#scanf. It parses values out of an input string according to a scanf format string, so it is the inverse of sprintf: where sprintf("%d", 42) renders "42", scanf("42", "%d") reads 42 back. It covers the full directive grammar β€” integers with base detection, hex/octal and MRI's quirky float forms, %s / %c, character-class sets %[…], widths, assignment suppression, and MRI's exact stopping semantics β€” with integers widening to *big.Int on overflow. It is bound into go-embedded-ruby by rbgo as a native module just like go-ruby-regexp and go-ruby-erb β€” differential-tested against MRI, 100% coverage, CI green across 6 arches.

Integer directives ready

%d / %u signed decimal, %i with base detection (0x=hex, leading 0=octal), %x / %X hex and %o octal β€” values widening transparently to arbitrary-precision *big.Int the moment they overflow int, just like Ruby’s Integer.

Float directives ready

%a / %e / %f / %g and their uppercase forms, including hexadecimal floats (0x1.8p1), MRI’s 123.e+3 form, and Β±Infinity saturation on overflow β€” matching MRI’s quirky float grammar byte-for-byte.

Strings, chars & sets ready

%s (a run of non-whitespace), %c (a single character or n with a width, which does not skip leading whitespace), and character-class sets %[…] / %[^…] with ranges, POSIX named classes (%[[:alpha:]]), and width bounds.

Widths & suppression ready

A decimal field width on any directive (%3d, %5s, %4f), and the assignment-suppression * flag (%*d) that consumes input but emits no value; %% matches a literal %.

MRI stopping semantics ready

Scanning stops at the first non-match, at end of input, or when the format is exhausted, returning the values converted so far β€” a partial match yields a shorter slice, no match an empty one. Scan runs once; ScanAll repeats the format until input is exhausted.

Differential oracle & coverage ready

A wide corpus β€” every directive, width, set, suppression flag, literal, and partial/failed match, in both single and block forms β€” scanned here and by the system ruby (String#scanf) and compared #inspect-for-#inspect; 100% coverage, gofmt + go vet clean, green across all six 64-bit Go arches.

A faithful port of Ruby's scanf gem in pure Go, cgo disabled, so it cross-compiles and embeds anywhere. It scans integers (%d/%i/%x/%o), floats (%a/%e/%f/%g, including hex floats), %s / %c, character-class sets %[…], field widths, and assignment suppression β€” matching MRI's quirky float grammar and stopping semantics byte-for-byte. Validated differentially against the system ruby binary (String#scanf). It is a standalone, reusable module bound into the sibling org github.com/go-embedded-ruby.