Parsing with the Nom Crate

C…
crusty.rustacean
Published on December 13, 2025

In late 2023 and early 2024, I was mildly obsessed with the `nom` crate. I returned to it for Day 10 of AoC

notes
nom programming parsing rust crates
0 likes

I’m working on Day 10 of Advent of Code. I wanted to re-visit the nomcrate. I had Claude guide me through how to parse the sample input in the problem defintion. I’ll return to and embellish this post later, but for now I wanted to make it into a “note to self”.

// src/main.rs

// dependencies
use nom::branch::alt;
use nom::character::complete::{char, space1, u32 as nom_u32};
use nom::combinator::{map, value};
use nom::multi::{many1, separated_list1};
use nom::sequence::delimited;
use nom::{IResult, Parser};

fn parse_light(input: &str) -> IResult<&str, bool> {
    alt((value(false, char('.')), value(true, char('#')))).parse(input)
}

fn parse_pattern(input: &str) -> IResult<&str, Vec<bool>> {
    delimited(char('['), many1(parse_light), char(']')).parse(input)
}

fn parse_button(input: &str) -> IResult<&str, Vec<usize>> {
    delimited(
        char('('),
        separated_list1(char(','), map(nom_u32, |n| n as usize)),
        char(')'),
    )
    .parse(input)
}

fn parse_buttons(input: &str) -> IResult<&str, Vec<Vec<usize>>> {
    separated_list1(space1, parse_button).parse(input)
}

fn parse_joltages(input: &str) -> IResult<&str, Vec<u32>> {
    delimited(char('{'), separated_list1(char(','), nom_u32), char('}')).parse(input)
}

fn parse_machine(input: &str) -> IResult<&str, FactoryMachine> {
    map(
        (parse_pattern, space1, parse_buttons, space1, parse_joltages),
        |(pattern, _, buttons, _, joltages)| FactoryMachine {
            pattern,
            buttons,
            joltages,
        },
    )
    .parse(input)
}

fn parse_machines(input: &str) -> IResult<&str, Vec<FactoryMachine>> {
    separated_list1(char('\n'), parse_machine).parse(input)
}

#[derive(Debug)]
struct FactoryMachine {
    pattern: Vec<bool>,
    buttons: Vec<Vec<usize>>,
    joltages: Vec<u32>,
}

fn main() {
    let sample_input = "[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}\n[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}\n[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}";

    let factory_machine = parse_machines(sample_input).unwrap();

    println!("{:?}", factory_machine.1);
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn parse_light_returns_one_returns_true_or_false() {
        let input = ".##.";
        let result = parse_light(input).unwrap();
        assert_eq!(result, ("##.", false));
    }

    #[test]
    fn parse_pattern_handles_brackets() {
        let input = "[.##.]";
        let result = parse_pattern(input).unwrap();
        assert_eq!(result, ("", vec![false, true, true, false]));
    }

    #[test]
    fn parse_button_single_index() {
        let input = "(3)";
        let result = parse_button(input).unwrap();
        assert_eq!(result, ("", vec![3]));
    }

    #[test]
    fn parse_button_multiple_indices() {
        let input = "(1,3)";
        let result = parse_button(input).unwrap();
        assert_eq!(result, ("", vec![1, 3]));
    }

    #[test]
    fn parse_buttons_multiple() {
        let input = "(3) (1,3) (2)";
        let result = parse_buttons(input).unwrap();
        assert_eq!(result, ("", vec![vec![3], vec![1, 3], vec![2]]));
    }

    #[test]
    fn parse_joltages_single() {
        let input = "{3,5,4,7}";
        let result = parse_joltages(input).unwrap();
        assert_eq!(result, ("", vec![3, 5, 4, 7]));
    }
}

Parses the sample input from the problem definition. Takes this:

[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}

and gives me this:

[FactoryMachine { pattern: [false, true, true, false], buttons: [[3], [1, 3], [2], [2, 3], [0, 2], [0, 1]], joltage: [3, 5, 4, 7] }, FactoryMachine { pattern: [false, false, false, true, false], buttons: [[0, 2, 3, 4], [2, 3], [0, 4], [0, 1, 2], [1, 2, 3, 4]], joltage: [7, 5, 12, 7, 2] }, FactoryMachine { pattern: [false, true, true, true, false, true], buttons: [[0, 1, 2, 3, 4], [0, 3, 4], [0, 1, 2, 4, 5], [1, 2]], joltage: [10, 11, 11, 5, 10, 5] }]

Which is my chosen data structure for solving the problem.

C…
crusty.rustacean

Comments

Loading comments...