home ~ projects ~ socials

Match A String That's Not At The Start Of A Source String In Rust With nom

The goal of this code is to find the last one.

```cargo
[dependencies]
nom = "7.1.3"
```

use nom::bytes::complete::is_a;
use nom::sequence::preceded;
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::character::complete::multispace1;
use nom::combinator::opt;
use nom::combinator::not;
use nom::sequence::tuple;
use nom::multi::many0;
use nom::multi::many1;
use nom::IResult;
use nom::Parser;

fn main() {
  let source = r"this is ~~ status: bravo ~~ id: alfaXthe match".to_string();
  match get_ids(&source) {
    Ok((_, ids)) => {
      dbg!(ids);
      ()
    }
    Err(e) => {
      dbg!(e);
      ()
    }
  }
}

fn get_ids(source: &str) -> IResult<&str, Vec<&str>> {
  let (source, ids) = many1(get_id).parse(source)?;
  Ok((source, ids))
}

fn get_id(source: &str) -> IResult<&str, &str> {
  let (source, _) = many0(
    tuple((
      opt(is_not("~")), 
      not(tag("~~ id:")),
      is_a("~")
    ))
  ).parse(source)?;
  let (source, id) = preceded(
    tuple((
        is_not("~~"), 
        tag("~~ id:"), 
        multispace1
      )),
    is_not("X")
  ).parse(source)?;
  Ok((source, id))
}
Output:
[/Users/alan/.cargo/target/55/19854259915251/_active_nvim_run:23:7] ids = [
    "alfa",
]

This code is to find just one

```cargo
[dependencies]
nom = "7.1.3"
```

use nom::bytes::complete::is_a;
use nom::sequence::preceded;
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::character::complete::multispace1;
use nom::combinator::opt;
use nom::combinator::not;
use nom::sequence::tuple;
use nom::multi::many0;
use nom::IResult;
use nom::Parser;

fn main() {
  let source = r"this is ~~ status: bravo ~~ id: alfaXthe match".to_string();
  match get_id(&source) {
    Ok((_, id)) => println!("{}", id),
    Err(e) => println!("ERROR: {}", e)
  }
}

fn get_id(source: &str) -> IResult<&str, &str> {
  let (source, _) = many0(
    tuple((
      opt(is_not("~")), 
      not(tag("~~ id:")),
      is_a("~")
    ))
  ).parse(source)?;
  let (source, id) = preceded(
    tuple((
        is_not("~~"), 
        tag("~~ id:"), 
        multispace1
      )),
    is_not("X")
  ).parse(source)?;
  Ok((source, id))
}
Output:
alfa

Notes

  • The opt is to handle cases where the ID is the first thing in the file. Without it, it never makes it past the first character
-- end of line --