4个版本 (2个破坏性更新)

0.3.0 2023年1月16日
0.2.1 2022年7月10日
0.2.0 2021年10月23日
0.1.0 2021年7月16日

#37 in 命令行界面

Download history 17959/week @ 2024-04-22 19096/week @ 2024-04-29 19903/week @ 2024-05-06 17994/week @ 2024-05-13 17679/week @ 2024-05-20 17926/week @ 2024-05-27 18045/week @ 2024-06-03 18949/week @ 2024-06-10 20836/week @ 2024-06-17 18670/week @ 2024-06-24 16227/week @ 2024-07-01 18759/week @ 2024-07-08 24646/week @ 2024-07-15 27674/week @ 2024-07-22 27972/week @ 2024-07-29 30791/week @ 2024-08-05

每月下载量112,957
87 个crate中使用 (直接使用67个)

MIT 许可证

71KB
1K SLoC

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.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::* 会添加一个 .parse() 方法,类似于 str::parse
    • 调用 parser.value() 是告诉 Parser -n 需要一个值的。
  • Value 表示一个独立的参数。
    • if thing.is_none() 是处理位置参数的有用模式。如果我们已经找到了 thing,我们将其传递给另一个情况。
    • 它还包含一个 OsString
      • .string() 方法将其解码为普通的 String
  • 如果我们不知道如何处理一个参数,我们使用 return Err(arg.unexpected()) 将其转换为错误信息。
  • 字符串可以被提升为错误,用于自定义错误信息。

这涵盖了库中的大部分功能。Lexopt 为你做了非常少的事情。

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

命令行语法

以下约定得到支持

  • 短选项(-q
  • 长选项(--verbose
  • -- 用于标记选项的结束
  • = 用于分隔选项和值(--option=value-o=value
  • 空格用于分隔选项和值(--option value-o value
  • 未分隔的短选项(-ovalue
  • 组合短选项(-abc 表示 -a -b -c
  • 带有可选参数的选项(类似于 GNU sed 的 -i,它可以独立使用,也可以作为 -iSUFFIX)(Parser::optional_value())
  • 带有多个参数的选项(Parser::values())

这些不支持

  • 单划线长选项(如 find 的 -name
  • 缩写长选项(GNU 的 getopt 允许你写出 --num 而不是 --number,如果它可以无歧义地展开)

Parser::raw_args()Parser::try_raw_args() 提供了一种消费原始命令行参数的逃生门。请参阅 examples/nonstandard.rs,了解解析非标准选项语法的示例。

Unicode

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

短选项可以是 Unicode,但只能是一个码点(一个 char)。

选项可以与非 Unicode 参数结合使用。也就是说,--option=��� 不会导致错误或损坏值。

如果选项本身不是有效的 Unicode,则它们将被 String::from_utf8_lossy 进行修补。这意味着您可能会在稍后它们未被识别时引发错误。

为什么?

对于特定的应用程序,我在寻找一个小的、严格正确的解析器。有其他紧凑的参数解析库,但我找不到一个能够处理 OsString 并忠实实现参数语法的所有繁琐细节的库。

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

为什么不呢?

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

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

另请参阅

无运行时依赖