scan-rules
This crate provides some macros for quickly parsing values out of text. Roughly speaking, it does the inverse of the print!
/format!
macros; or, in other words, a similar job to scanf
from C.
The macros of interest are:
readln!
- reads and scans a line from standard input.try_readln!
- like readln!
, except it returns a Result
instead of panicking.scan!
- scans the provided string.If you are interested in implementing support for your own types, see the ScanFromStr
trait.
The available abstract scanners can be found in the scanner
module.
Links
Here is a simple CLI program that asks the user their name and age. You can run this using cargo run --example ask_age
.
```rust
use scan_rules::scanner::Word;
fn main() {
print!("What's your name? ");
let name: String = readln! { (let name: Word
print!("Hi, {}. How old are you? ", name);
readln! {
(let age) => {
// ^~~~~~^ implicitly typed variable binding
let age: i32 = age;
println!("{} years old, huh? Neat.", age);
},
(..other) => println!("`{}` doesn't *look* like a number...", other),
// ^~~~~~^ bind to any input "left over"
}
} ```
This example shows how to parse one of several different syntaxes. You can run this using cargo run --example scan_data
.
```rust
use std::collections::BTreeSet;
// Word
is an "abstract" scanner; rather than scanning itself, it scans some
// other type using custom rules. In this case, it scans a word into a
// string slice. You can use Word<String>
to get an owned string.
use scan_rules::scanner::Word;
enum Data {
Vector(i32, i32, i32),
Truthy(bool),
Words(Vec
fn main() { print!("Enter some data: "); let data = readln! { ("<", let x, ",", let y, ",", let z, ">") => Data::Vector(x, y, z), // ^ pattern terms are comma-separated // ^~^ literal text match
// Rules are tried top-to-bottom, stopping as soon as one matches.
(let b) => Data::Truthy(b),
("yes") => Data::Truthy(true),
("no") => Data::Truthy(false),
("words:", [ let words: Word<String> ],+) => Data::Words(words),
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~^ repetition pattern
// ^ one or more matches
// ^ matches must be comma-separated
("lucky numbers:", [ let ns: i32 ]*: BTreeSet<_>) => Data::Lucky(ns),
// collect into specific type ^~~~~~~~~~~~^
// ^ zero or more (you might be unlucky!)
// (no separator this time)
// Rather than scanning a sequence of values and collecting them into
// a `BTreeSet`, we can instead scan the `BTreeSet` *directly*. This
// scans the syntax `BTreeSet` uses when printed using `{:?}`:
// `{1, 5, 13, ...}`.
("lucky numbers:", let ns) => Data::Lucky(ns),
(..other) => Data::Other(String::from(other))
};
println!("data: {:?}", data);
} ```
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.