1 个不稳定版本

0.1.0 2021年7月22日

#756命令行界面

MIT 许可证

52KB
813

Lexopt

Crates.io API reference MSRV CI

Lexopt 是一个 Rust 的参数解析器。它试图采用最简单的设计,同时确保正确性。它的简单性使得使用起来略显繁琐。

Lexopt 的特点:

  • 小巧:单个文件,无依赖,无宏。易于审计或商业化。
  • 正确:支持标准约定,避免歧义。经过测试和模糊测试。
  • 严格:参数作为 OsString 返回,强制您显式转换。这可以让您处理坏编码的文件名。
  • 命令式:选项按找到的顺序返回,无需预先声明。
  • 简约:仅提供最基本的功能。
  • 不友好:没有帮助生成,错误消息经常缺乏上下文。

示例

struct Args {
    thing: String,
    number: u32,
    shout: bool,
}

fn parse_args() -> Result<Args, lexopt::Error> {
    use lexopt::prelude::*;

    let mut thing = None;
    let mut number = 1;
    let mut shout = false;
    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('n') | Long("number") => {
                number = parser.value()?.parse()?;
            }
            Long("shout") => {
                shout = true;
            }
            Value(val) if thing.is_none() => {
                thing = Some(val.into_string()?);
            }
            Long("help") => {
                println!("Usage: hello [-n|--number=NUM] [--shout] THING");
                std::process::exit(0);
            }
            _ => return Err(arg.unexpected()),
        }
    }

    Ok(Args {
        thing: thing.ok_or("missing argument THING")?,
        number,
        shout,
    })
}

fn main() -> Result<(), lexopt::Error> {
    let args = parse_args()?;
    let mut message = format!("Hello {}", args.thing);
    if args.shout {
        message = message.to_uppercase();
    }
    for _ in 0..args.number {
        println!("{}", message);
    }
    Ok(())
}

让我们一步步来看

  • 我们使用 Parser::from_env() 开始解析。
  • 我们循环调用 parser.next() 以获取所有参数,直到它们用完。
  • 我们对参数进行匹配。 ShortLong 指示一个选项。
  • 要获取属于选项的值(如 10-n 10 中)我们调用 parser.value()
    • 这返回一个标准的 OsString
    • 为了方便,使用use lexopt::prelude::*会添加一个类似于str::parse.parse()方法。
  • Value表示一个独立的参数。在这种情况下,是一个文件名。
    • if thing.is_none()是处理位置参数的一个有用模式。如果我们已经找到了thing,我们将它传递给另一个情况。
    • 它还包含一个OsString
      • 标准的.into_string()方法可以将其解码为普通的String
  • 如果我们不知道如何处理一个参数,我们使用return Err(arg.unexpected())将其转换为错误消息。
  • 字符串可以提升为错误以生成自定义错误消息。

这几乎涵盖了库中的所有功能。Lexopt为您做的事情很少。

有关带有有用模式的较大示例,请参阅examples/cargo.rs

命令行语法

支持以下约定

  • 短选项(-q
  • 长选项(--verbose
  • --用于标记选项的结束
  • =用于将长选项与值分开(--option=value
  • 空格用于将选项与值分开(--option value-f value
  • 未分隔的短选项(-fvalue
  • 组合短选项(-abc表示-a -b -c

以下不支持

  • 短选项的-f=value
  • 具有可选参数的选项(如GNU sed的-i,它可以用作独立的或作为-iSUFFIX
  • 单破折号长选项(如find的-name
  • 缩写长选项(GNU的getopt允许您在可以无歧义地展开的情况下使用--num代替--number

Unicode

此库支持Unicode,同时容忍非Unicode参数。

短选项可以是Unicode,但只能是一个代码点。(如果您需要整个图形簇,可以使用长选项。如果您需要规范化,您自己处理,但这可以做到。)

选项可以与非Unicode参数组合。也就是说,--option=���不会导致错误或破坏值。这非常难以支持:请参阅os_str_bytes

选项本身如果不合法Unicode,会被补丁为 String::from_utf8_lossy。这意味着你之后可能会因为无法识别而引发错误。

为什么?

为了特定的应用,我在寻找一个小型且严格正确的解析器。虽然有一些紧凑的参数解析库,但我没有找到能够处理OsString并且忠实实现参数语法所有复杂细节的库。

如果需要大量控制,例如精确的参数顺序很重要或不是所有选项都提前知道,这个库可能也很有用。它更像是词法分析器而不是解析器。

为什么不呢?

如果你不关心以下情况,则可能不值得使用此库:

  • 你不在乎非Unicode参数
  • 你不在乎精确的兼容性和正确性
  • 你不在乎代码大小
  • 你关心出色的错误消息
  • 你讨厌样板代码

另请参阅

  • clap/structopt:功能非常全面。我所知道的唯一一个真正正确处理无效Unicode的Rust参数解析器,如果使用得当。体积较大。
  • arghgumdrop:更加轻量级,但仍然方便,足够强大,足以满足大多数需求。在无效Unicode上引发恐慌。
    • argh 遵循 Fuchsia规范,因此不支持 --option=value-ovalue,只支持 --option value-o value
  • pico-args:比lexopt稍小,更容易使用(但不太严格)。
  • ap:我没有使用过它,但它似乎支持迭代解析,同时比lexopt更简单。
  • libc的 getopt

pico-args有一个有趣的表格,列出了不同解析器的构建时间和代码大小。我已经重新运行了测试,并添加了lexopt(使用examples/pico_test_app.rs中的程序)

null lexopt pico-args clap gumdrop structopt argh
二进制开销 0KiB 14.5KiB 13.5KiB 372.8KiB 17.7KiB 371.2KiB 16.8KiB
构建时间 0.9s 1.7s 1.6s 13.0s 7.5s 17.0s 7.5s
依赖项数量 0 0 0 8 4 19 6
测试版本 - 0.1.0 0.4.2 2.33.3 0.8.0 0.3.22 0.1.4

(测试在x86_64 Linux上使用Rust 1.53和cargo-bloat 0.10.1进行。)

无运行时依赖