nom README

The project's README from github.com/rust-bakery/nom. As one markdown file: README.md.

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 is a parser combinators library written in Rust. Its goal is to provide tools to build safe parsers without compromising the speed or memory consumption. To that end, it uses extensively Rust's strong typing and memory safety to produce fast and correct parsers, and provides functions, macros and traits to abstract most of the error prone plumbing.

nom logo in CC0 license, by Ange Albertini

nom will happily take a byte out of your files :)

Example

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

Documentation

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 was designed to properly parse binary formats from the beginning. Compared to the usual handwritten C parsers, nom parsers are just as fast, free from buffer overflow vulnerabilities, and handle common patterns for you:

Example projects:

Text format parsers

While nom was made for binary format at first, it soon grew to work just as well with text formats. From line based formats like CSV, to more complex, nested formats such as JSON, nom can manage it, and provides you with useful tools:

Example projects:

Programming language parsers

While programming language parsers are usually written manually for more flexibility and performance, nom can be (and has been successfully) used as a prototyping parser for a language.

nom will get you started quickly with powerful custom error types, that you can leverage with nom_locate to pinpoint the exact line and column of the error. No need for separate tokenizing, lexing and parsing phases: nom can automatically handle whitespace parsing, and construct an AST in place.

Example projects:

Streaming formats

While a lot of formats (and the code handling them) assume that they can fit the complete data in memory, there are formats for which we only get a part of the data at once, like network formats, or huge files. nom has been designed for a correct behaviour with partial data: If there is not enough data to decide, nom will tell you it needs more instead of silently returning a wrong result. Whether your data comes entirely or in chunks, the result should be the same.

It allows you to build powerful, deterministic state machines for your protocols.

Example projects:

Parser combinators

Parser combinators are an approach to parsers that is very different from software like lex and yacc. Instead of writing the grammar in a separate file and generating the corresponding code, you use very small functions with very specific purpose, like "take 5 bytes", or "recognize the word 'HTTP'", and assemble them in meaningful patterns like "recognize 'HTTP', then a space, then a version". The resulting code is small, and looks like the grammar you would have written with other parser approaches.

This has a few advantages:

Technical features

nom parsers are for:

Some benchmarks are available on GitHub.

Rust version requirements (MSRV)

The 8.0 series of nom supports Rustc version 1.65 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 = "8"

There are a few compilation features:

You can configure those features like this:

[dependencies.nom]
version = "8"
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!

nom (rust-bakery/nom)

Searching Database…

10.5K ·GitHub
What is this?nom is a parser combinator library for Rust: you build safe parsers by composing small functions, without giving up speed or memory efficiency.
Is it a library I import into my code, or a tool I run?A library. You add it to a Cargo project from crates.io and write parsers as plain Rust functions — there is no binary to run and no separate grammar file.
How do I add it to a project?Run cargo add nom in your Cargo project. To learn, the README points to the Nominomicon guide, reference docs and a list of every combinator with its behaviour.
Do I need a recent Rust toolchain for it?Just a Rust toolchain: nom 8 requires Rustc 1.65 or newer, and that minimum only moves at the next major release, so minor updates stay compatible.
Are there cases where nom is not the best fit?For full programming languages, handwritten parsers can still win on flexibility and speed — nom positions itself as a prototyping parser there, with custom error types and nomlocate pinpointing the exact line and column.
How is writing a parser with nom different from using lex or yacc?No grammar file or generated code: you assemble tiny functions like 'take 5 bytes' or 'recognize HTTP' directly in Rust. The code stays small, reads close to the grammar you would have written, and each piece can be unit-tested on its own.
What kinds of formats do people parse with it?A lot: binary formats (FLV, Matroska, tar), text formats (CSV, TOML, INI), programming languages (PHP, SQL, Python) and network protocols (HTTP, TLS, DNS, DHCP) — the README lists dozens of real parsers built with nom.
Can it handle data that arrives in chunks, like from a network socket?Yes, streaming is a first-class case: when there is not enough data to decide, nom asks for more instead of silently returning a wrong result, so chunked and whole input produce the same outcome — handy for protocol state machines.
Is it actually fast?The README cites benchmarks where nom outperforms combinator libraries like Parsec and attoparsec, some regex engines, and even handwritten C parsers. Parsing is also zero-copy: results reference slices of the input instead of copying it.
What are similar projects?antlr4, liteparse, go, kcp, parsedown, gjson, hyper, REDox
Size
10.5 MB
Stars
10.5K
Updated
CommitAug 26
Age
11y
Commits · 90 Days