Skip to content

fswdev/nom

 
 

Repository files navigation

nom, eating data byte by byte

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

nom是一个用Rust编写的解析器组合库。它的目标是在不影响速度或内存消耗的情况下提供一个构建安全解析器的工具。因此,nom使用了Rust强大的类型和内存安全性来生成快速正确的解析器,并提供函数、宏和trait来抽象大多数容易出错的解析工作。

nom logo in CC0 license, by Ange Albertini

nom 会很乐意从你的文件中取出一个字节 :)

示例

Hexadecimal color parser:

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

文档

If you need any help developing your parsers, please ping geal on IRC (Libera, Geeknode, OFTC), go to #nom-parsers on Libera IRC, or on the Gitter chat room.

Why use nom

If you want to write:

Binary format parsers

nom从一开始就被设计用于正确解析二进制格式。与通常的手写C语法分析器相比, nom语法分析器同样快速,不受缓冲区溢出漏洞,并可以为您处理常见模式:

  • TLV
  • Bit level parsing
  • Hexadecimal viewer in the debugging macros for easy data analysis
  • Streaming parsers for network formats and huge files

Example projects:

Text format parsers

虽然nom最初是为二进制格式而设计的,但很快nom就适用于文本格式的解析。 从基于行的简单格式(CSV等),到复杂的嵌套格式(JSON), nom都可以处理它,并为您提供有用的工具:

  • Fast case insensitive comparison
  • Recognizers for escaped strings
  • Regular expressions can be embedded in nom parsers to represent complex character patterns succinctly
  • Special care has been given to managing non ASCII characters properly

Example projects:

Programming language parsers

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

nom将让您快速开始使用强大的自定义错误类型,您可以使用nom_locate 以精确定位错误的确切行和列。不需要单独的标记化、词法分析和解析阶段:nom可以自动处理空白解析,并就地构建AST。

Example projects:

Streaming formats

虽然很多格式(以及处理它们的代码)都认为它们可以容纳内存中的完整数据,但也有一些格式我们一次只能获得部分数据, 比如网络格式或大文件。 nom是为部分数据的正确行为而设计的:如果没有足够的数据来决定,nom会告诉你它需要更多的数据, 而不是默默地返回错误的结果。无论你的数据是完整的还是大块的,结果都应该是一样的。

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

Example projects:

Parser combinators

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

nom的几个优点:

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

Technical features

nom解析器用于:

  • [x]byte-oriented:基本类型为“&[u8]”,解析器将尽可能多地在字节数组切片上工作(但不限于此)
  • [x]bit-oriented:nom可以将字节片寻址为位流
  • [x]string-oriented:同样类型的组合子也可以应用于UTF-8字符串
  • [x]zero-copy:如果解析器返回其输入数据的子集,它将返回该输入的切片,而不进行复制
  • [x]streaming:nom可以处理部分数据,并检测何时需要更多数据才能产生正确的结果
  • [x]descriptive errors:解析器可以聚合一个错误代码列表,其中包含指向递增输入切片的指针。这些错误列表可以进行模式匹配,以提供有用的消息。
  • [x]custom error types:您可以提供特定的类型来改进解析器返回的错误
  • [x]safe parsing:nom利用了Rust的安全内存处理和强大的类型,解析器通常会被模糊化,并用真实世界的数据进行测试。到目前为止,模糊化发现的唯一缺陷是在nom之外编写的代码中
  • [x]speed:基准测试表明,nom解析器通常优于许多解析器组合子库,如Parsec和attoparsec,一些正则表达式引擎,甚至手写C解析器

Some benchmarks are available on GitHub.

Rust version requirements (MSRV)

The 7.0 series of nom supports Rustc version 1.56 or greater.

The current policy is that this will only be updated in the next major nom release.

Installation

nom is available on crates.io and can be included in your Cargo enabled project like this:

[dependencies]
nom = "7"

There are a few compilation features:

  • alloc: (activated by default) if disabled, nom can work in no_std builds without memory allocators. If enabled, combinators that allocate (like many0) will be available
  • std: (activated by default, activates alloc too) if disabled, nom can work in no_std builds

You can configure those features like this:

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

Related projects

Parsers written with nom

Here is a (non exhaustive) list of known projects using nom:

Want to create a new parser using nom? A list of not yet implemented formats is available here.

Want to add your parser here? Create a pull request for it!

Contributors

nom is the fruit of the work of many contributors over the years, many thanks for your help!

About

Rust parser combinator framework

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Rust 100.0%