num2phrase 0.1.0

Convert long number to a sequence of memorisable phrase with combination of short numbers
Documentation
// Minimal regex-like tokenizer using nom
use nom::{IResult, branch::alt, bytes::complete::{tag, take_while1, take_until}, character::complete::{anychar, char, none_of}, combinator::{map, recognize}, multi::many0, sequence::{delimited, preceded}};

#[derive(Debug, PartialEq)]
pub enum Token {
	Literal(char),
	Dot,
	Star,
	Plus,
	Question,
	Custom(String),
}

// Parser for a custom token, e.g. <DIGIT>
fn custom_token(input: &str) -> IResult<&str, Token> {
	map(
		delimited(char('<'), take_until(">"), char('>')),
		|s: &str| Token::Custom(s.to_string()),
	)(input)
}

// Parser for a single token
fn token(input: &str) -> IResult<&str, Token> {
	alt((
		map(char('.'), |_| Token::Dot),
		map(char('*'), |_| Token::Star),
		map(char('+'), |_| Token::Plus),
		map(char('?'), |_| Token::Question),
		custom_token,
		map(none_of(".*+?<>"), |c| Token::Literal(c)),
	))(input)
}

// Parser for a sequence of tokens
pub fn tokenize(input: &str) -> IResult<&str, Vec<Token>> {
	many0(token)(input)
}

#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn test_tokenize() {
		let input = "a.b*<DIGIT>?";
		let (_, tokens) = tokenize(input).unwrap();
		assert_eq!(tokens, vec![
			Token::Literal('a'),
			Token::Dot,
			Token::Literal('b'),
			Token::Star,
			Token::Custom("DIGIT".to_string()),
			Token::Question,
		]);
	}
}