crscanf v0.2.0
Scanf
This shard provides a compile-time scanf(fmt) macro backed by C sscanf.
scanf(fmt) returns a lambda that parses an input String and returns a typed Tuple.
Installation
Add scanf to your dependencies in your shard.yml file:
dependencies:
scanf:
github: tenebrousedge/crscanf
branch: master
Then run shards install.
Usage
This shard exposes a global scanf macro:
fmtmust be a compile-time string literal.- The returned lambda takes one
Stringinput. - The lambda returns a typed
Tuple.
Example:
a = scanf("%3s %d").call("abc 123")
puts a #=> {"abc", 123}
puts typeof(a) #=> Tuple(String, Int32)
lam = scanf("%f -- %c")
b = lam.call("1234 -- q2")
puts b #=> {1234.0, "q"}
puts typeof(b) #=> Tuple(Float32, String)
Supported Surface
| Feature | Status |
|---|---|
%d, %i, %u, %o, %x, %X |
Supported |
hh, h, l, ll integer modifiers |
Supported |
%f, %F, %e, %E, %g, %G, %a, %A |
Supported |
l floating modifier |
Supported |
%c, %s, %[...] |
Supported |
Assignment suppression (*) |
Supported |
%n |
Supported (without width or suppression) |
%% |
Supported |
%p |
Unsupported (compile-time rejection) |
j, z, t |
Unsupported |
L |
Unsupported |
Wide-character conversions (%lc, %ls, %l[...]) |
Unsupported |
| Runtime format strings | Unsupported |
| Embedded NUL input | Rejected |
| Checked numeric overflow | Not guaranteed |
Semantics and Limits
- Format must be a compile-time string literal.
- Results are returned as a tuple.
- Suppressed assignments are omitted from the returned tuple.
- Literal-only formats return
Tuple.new. - Incomplete matches raise
Scanf::MatchError. - Trailing input after a completed format is permitted.
- Floating-point parsing and some character classification follow the active C locale.
- This library does not change process locale.
- Numeric input outside destination C type range is unsupported: libc may hit undefined behavior before Crystal regains control.
%cwidth is a maximum; fewer bytes may be read at end-of-input.
More Examples
Integers:
scanf("%d %i %x").call("42 010 ff") # => {42, 8, 255}
Strings:
scanf("%3s %s").call("abcdef rest") # => {"abc", "def"}
Scansets:
scanf("%[^,]").call("hello,world") # => {"hello"}
scanf("%[]]").call("]]]X") # => {"]]]"}
Suppression:
scanf("%*d %d").call("10 20") # => {20}
Failure handling:
begin
scanf("%dX").call("1Y")
rescue Scanf::MatchError
puts "format did not complete"
end
Compile-time format rejection:
# This fails to compile: format must be a literal.
format = "%d"
scanf(format)
This shard intentionally targets string scanning through sscanf. Direct scanning from IO streams is not provided.
Warning
scanf is a dangerous tool. It can easily result in undefined behavior. Test your format strings carefully. This implementation has at least as many bugs as the C version, and likely more.
Development
This shard requires no special libraries, aside from the Crystal compiler. Bugs should be reported via the GitHub issues list.
Optional developer checks:
# Runtime suite under C locale
LC_ALL=C crystal spec
# Compile-time format harness
bash spec/format_compile_spec.sh
# Non-default stress target
crystal spec spec/stress_runtime.cr
Some Crystal toolchains can run under sanitizers. If your local compiler and linker support it, you can try:
crystal spec --link-flags "-fsanitize=address"
This sanitizer command is optional and is not required by the normal test suite.
Contributing
- Fork it (https://github.com/your-github-user/scanf/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
Contributors
- Kaia Leahy - creator and maintainer
crscanf
- 0
- 0
- 0
- 0
- 0
- about 4 hours ago
- June 17, 2026
MIT License
Fri, 07 Aug 2026 00:11:34 GMT