无需 std nom

一个基于字节、零拷贝的解析器组合库

96 个版本 (43 个稳定版)

8.0.0-alpha22024 年 5 月 5 日
7.1.3 2023 年 1 月 15 日
7.1.1 2022 年 3 月 14 日
7.1.0 2021 年 11 月 4 日
0.2.0 2015 年 3 月 24 日

#2解析器实现

Download history 1653294/week @ 2024-05-03 1706665/week @ 2024-05-10 1747596/week @ 2024-05-17 1628966/week @ 2024-05-24 1749761/week @ 2024-05-31 1819282/week @ 2024-06-07 1750788/week @ 2024-06-14 1761890/week @ 2024-06-21 1546643/week @ 2024-06-28 1650418/week @ 2024-07-05 1740194/week @ 2024-07-12 1783591/week @ 2024-07-19 1752370/week @ 2024-07-26 1890221/week @ 2024-08-02 2105865/week @ 2024-08-09 1725029/week @ 2024-08-16

7,798,705 每月下载量
用于 14,776 个 crate (1,956 直接使用)

MIT 许可证

660KB
13K SLoC

nom,逐字节吃掉数据

LICENSE Join the chat at https://gitter.im/Geal/nom Build Status Coverage Status crates.io Version Minimum rustc version

nom 是一个用 Rust 编写的解析器组合库。它的目标是提供构建安全解析器的工具,而不牺牲速度或内存消耗。为此,它广泛使用 Rust 的 强类型内存安全 来生成快速且正确的解析器,并提供函数、宏和特性来抽象大部分容易出错的底层代码。

nom logo in CC0 license, by Ange Albertini

nom 很乐意从您的文件中提取字节 :)

示例

十六进制颜色 解析器

use nom::{
  bytes::complete::{tag, take_while_m_n},
  combinator::map_res,
  sequence::Tuple,
  IResult,
  Parser,
};

#[derive(Debug, PartialEq)]
pub struct Color {
  pub red: u8,
  pub green: u8,
  pub blue: u8,
}

fn from_hex(input: &str) -> Result<u8, std::num::ParseIntError> {
  u8::from_str_radix(input, 16)
}

fn is_hex_digit(c: char) -> bool {
  c.is_digit(16)
}

fn hex_primary(input: &str) -> IResult<&str, u8> {
  map_res(
    take_while_m_n(2, 2, is_hex_digit),
    from_hex
  ).parse(input)
}

fn hex_color(input: &str) -> IResult<&str, Color> {
  let (input, _) = tag("#")(input)?;
  let (input, (red, green, blue)) = (hex_primary, hex_primary, hex_primary).parse(input)?;
  Ok((input, Color { red, green, blue }))
}

fn main() {
  println!("{:?}", hex_color("#2F14DF"))
}

#[test]
fn parse_color() {
  assert_eq!(
    hex_color("#2F14DF"),
    Ok((
      "",
      Color {
        red: 47,
        green: 20,
        blue: 223,
      }
    ))
  );
}

文档

如果您在开发解析器时需要任何帮助,请在 IRC(Libera、Geeknode、OFTC)上 ping geal,前往 Libera IRC 上的 #nom-parsers,或在 Gitter 聊天室

为什么使用 nom

如果您想编写

二进制格式解析器

nom 从一开始就被设计用来正确解析二进制格式。与通常的手写 C 解析器相比,nom 解析器具有相同的速度,没有缓冲区溢出漏洞,并为您处理常见模式

  • TLV
  • 位级解析
  • 在调试宏中的十六进制查看器,便于数据分析
  • 适用于网络格式和大型文件的流解析器

示例项目

文本格式解析器

虽然 nom 最初是为二进制格式制作的,但它很快就能很好地处理文本格式。从基于行的格式如 CSV 到更复杂的嵌套格式如 JSON,nom 都能管理,并提供有用的工具

  • 快速不区分大小写的比较
  • 识别转义字符串
  • 可以在 nom 解析器中嵌入正则表达式来简洁地表示复杂的字符模式
  • 特别关注正确处理非 ASCII 字符

示例项目

编程语言解析器

虽然编程语言解析器通常为了更大的灵活性和性能而手动编写,但 nom 可以(并且已经成功地)用作语言的原型解析器。

nom 将让您快速入门,提供强大的自定义错误类型,您可以使用 nom_locate 来精确定位错误的行和列。无需单独的标记化、词法分析和解析阶段:nom 可以自动处理空白解析,并在原地构建抽象语法树(AST)。

示例项目

流格式

虽然许多格式(及其处理它们的代码)假设它们可以将完整数据放入内存中,但还有一些格式,我们一次只能获取部分数据,例如网络格式或大文件。nom 已经设计为对部分数据进行正确处理:如果没有足够的数据来决定,nom 会告诉你需要更多的数据,而不是默默地返回错误的结果。无论您的数据是全部还是分块提供的,结果都应该是一样的。

它允许您为您的协议构建强大、确定性的状态机。

示例项目

解析器组合器

解析器组合器是解析器的一种方法,与 lexyacc 等软件非常不同。您不需要在单独的文件中编写语法并生成相应的代码,而是使用非常小且具有特定目的的函数,例如“取5个字节”或“识别单词‘HTTP’”,并将它们组合成有意义的模式,例如“识别‘HTTP’,然后是一个空格,然后是一个版本”。生成的代码很小,看起来就像您使用其他解析器方法编写的语法。

这有几个优点

  • 解析器小且易于编写
  • 解析器组件易于重用(如果它们足够通用,请将其添加到 nom 中!)
  • 解析器组件易于单独测试(单元测试和基于属性的测试)
  • 解析器组合代码看起来接近您会编写的语法
  • 您可以根据当前所需的数据构建部分解析器,并忽略其余部分

技术特性

nom 解析器适用于

  • 字节导向:基本类型是 &[u8],解析器尽可能在字节数组切片上工作(但不仅限于它们)
  • 位导向:nom 可以将字节数组切片作为位流来寻址
  • 字符串导向:相同类型的组合器也可以应用于 UTF-8 字符串
  • 零复制:如果解析器返回其输入数据的一个子集,它将返回该输入的切片,而无需复制
  • 流式处理:nom 可以在部分数据上工作,并在需要更多数据以产生正确结果时检测到这一点
  • 描述性错误:解析器可以聚合一系列错误代码,并带有指向受指责输入切片的指针。这些错误列表可以通过模式匹配来提供有用的消息。
  • 自定义错误类型:您可以为解析器返回的错误提供特定类型以提高错误
  • 安全解析:nom 利用 Rust 的安全内存处理和强大的类型,并且解析器通常会使用真实世界数据模糊测试和测试。到目前为止,通过模糊测试发现的唯一缺陷是在 nom 之外编写的代码中
  • 速度:基准测试表明,nom 解析器通常优于许多解析器组合库,如 Parsec 和 attoparsec,一些正则表达式引擎,甚至是手写的 C 解析器

一些基准测试可在 GitHub 上找到。

Rust 版本要求(MSRV)

nom 的 7.0 系列支持 Rustc 版本 1.56 或更高

当前政策是,这仅在下一个主要 nom 版本中更新。

安装

nom 可在 crates.io 上找到,并可以像这样包含在您的 Cargo 启用项目中

[dependencies]
nom = "7"

有几个编译功能

  • alloc:默认启用。如果禁用,nom可以在没有内存分配器的no_std构建中运行。如果启用,将可用分配的组合子(如many0
  • std:默认启用,同时也会启用alloc。如果禁用,nom可以在no_std构建中运行

您可以通过以下方式配置这些功能

[dependencies.nom]
version = "7"
default-features = false
features = ["alloc"]

相关项目

使用 nom 编写的解析器

以下是一些已知使用nom的项目列表(非详尽列表)

想要使用 nom 创建新的解析器?尚未实现的格式列表可在此处找到。

想要在此处添加您的解析器?创建一个拉取请求!

贡献者

nom 是多年来许多贡献者的工作成果,感谢您的帮助!

依赖项