#stdin #input #read #parse #parser

scan-rules

此软件包提供了一些宏,用于快速从文本中解析值。简而言之,它执行了 print!/format! 宏的相反操作;换句话说,与 C 中的 scanf 宏有类似的功能。

8 个版本

使用旧 Rust 2015

0.2.0 2016 年 11 月 7 日
0.1.3 2016 年 4 月 23 日
0.1.1 2016 年 2 月 5 日
0.0.4 2016 年 1 月 22 日

1251Rust 模式

Download history 68/week @ 2024-03-11 75/week @ 2024-03-18 84/week @ 2024-03-25 121/week @ 2024-04-01 97/week @ 2024-04-08 86/week @ 2024-04-15 77/week @ 2024-04-22 111/week @ 2024-04-29 222/week @ 2024-05-06 90/week @ 2024-05-13 72/week @ 2024-05-20 73/week @ 2024-05-27 54/week @ 2024-06-03 51/week @ 2024-06-10 87/week @ 2024-06-17 133/week @ 2024-06-24

339 每月下载量
8 crates 中使用

MIT/Apache

305KB
5K SLoC

scan-rules

此软件包提供了一些宏,用于快速从文本中解析值。简而言之,它执行了 print!/format! 宏的相反操作;换句话说,与 C 中的 scanf 宏有类似的功能。

感兴趣的宏包括

  • readln! - 从标准输入读取并扫描一行。
  • try_readln! - 与 readln! 类似,但它返回一个 Result 而不是引发恐慌。
  • scan! - 扫描提供的字符串。

此外还有两个便捷宏

  • let_scan! - 扫描字符串并将捕获的值直接绑定到局部变量。仅支持 一个 模式,如果不匹配则引发恐慌。
  • let_scanln! - 读取并扫描一行从标准输入,并将捕获的值直接绑定到局部变量。仅支持 一个 模式,如果不匹配则引发恐慌。

如果您想实现对您自己的类型的支持,请参阅 ScanFromStr 特性。

可用的抽象扫描器可以在 scanner 模块中找到。

链接

兼容性

scan-rulesrustc 版本 1.6.0 及更高版本兼容。

  • 由于破坏性更改,scan-rulesregex 版本 0.1.66 及更高版本不兼容。

  • rustc < 1.10 不会有 let_scanln! 宏。

  • rustc < 1.7 只会为 EverythingIdentLineNonSpaceNumberWordWordish 扫描器提供针对 &strString 输出类型的具体实现。1.7 及更高版本将为所有输出类型提供泛型实现,例如 &str: Into<Output>

  • rustc < 1.6 明确不支持,因为 Rust 本身有破坏性更改。

快速示例

以下是一个简单的 CLI 程序,它会询问用户的姓名和年龄。您可以使用以下命令运行此程序:cargo run --example ask_age

#[macro_use] extern crate scan_rules;

use scan_rules::scanner::Word;

fn main() {
    print!("What's your name? ");
    let name: String = readln! { (let name: Word<String>) => name };
    //                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ rule
    //                                                       ^~~^ body
    //                           ^~~~~~~~~~~~~~~~~~~~~~~^ pattern
    //                            ^~~~~~~~~~~~~~~~~~~~~^ variable binding

    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"
    }

    print!("Ok.  What... is your favourite colour? (R, G, B): ");
    let_scanln!(let r: f32, ",", let g: f32, ",", let b: f32);
    //          ^~~~^            ^~~~^            ^~~~^
    // Scans and binds three variables without nesting scope.
    // Panics if *anything* goes wrong.
    if !(g < r && g < b && b >= r * 0.25 && b <= r * 0.75) {
        println!("Purple's better.");
    } else {
        println!("Good choice!");
    }
}

此示例展示了如何解析几种不同的语法之一。您可以使用以下命令运行此程序:cargo run --example scan_data

#[macro_use] extern crate scan_rules;

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;

#[derive(Debug)]
enum Data {
    Vector(i32, i32, i32),
    Truthy(bool),
    Words(Vec<String>),
    Lucky(BTreeSet<i32>),
    Other(String),
}

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);
}

此示例演示了使用运行时扫描器和 let_scan! 便利宏。您可以使用以下命令运行此程序:cargo run --example runtime_scanners

//! **NOTE**: requires the `regex` feature.
#[macro_use] extern crate scan_rules;

fn main() {
    use scan_rules::scanner::{
        NonSpace, Number, Word,             // static scanners
        max_width_a, exact_width_a, re_str, // runtime scanners
    };

    // Adapted example from <https://cppreference.cn/w/cpp/io/c/fscanf>.
    let inp = "25 54.32E-1 Thompson 56789 0123 56ß水";

    // `let_scan!` avoids the need for indentation and braces, but only supports
    // a single pattern, and panics if anything goes wrong.
    let_scan!(inp; (
        let i: i32, let x: f32, let str1 <| max_width_a::<NonSpace>(9),
    //               use runtime scanner ^~~~~~~~~~~~~~~~~~~~~~~~~~~~^
    //          limit maximum width of a... ^~~~~~~~~~^
    //                      ...static NonSpace scanner... ^~~~~~~^
    //                                                      9 bytes ^
        let j <| exact_width_a::<i32>(2), let y: f32, let _: Number,
    //        ^~~~~~~~~~~~~~~~~~~~~~~~~^ scan an i32 with exactly 2 digits
        let str2 <| re_str(r"^[0-9]{1,3}"), let warr: Word
    //           ^~~~~~~~~~~~~~~~~~~~~~~~^ scan using a regular expression
    ));

    println!(
        "Converted fields:\n\
            i = {i:?}\n\
            x = {x:?}\n\
            str1 = {str1:?}\n\
            j = {j:?}\n\
            y = {y:?}\n\
            str2 = {str2:?}\n\
            warr = {warr:?}",
        i=i, j=j, x=x, y=y,
        str1=str1, str2=str2, warr=warr);
}

许可证

根据您的选择,许可协议为以下之一:

贡献

除非您明确声明,否则您提交给包含在您的工作中的任何贡献都将根据上述方式双许可,没有任何额外的条款或条件。

依赖项

~1.1–1.9MB
~39K SLoC