duckling 0.4.0

A Rust port of Facebook's Duckling library for parsing natural language into structured data
Documentation
use crate::pattern::regex;
use crate::types::{Rule, TokenData};

use super::OrdinalData;

fn parse_ja_numeral(s: &str) -> Option<i64> {
    if let Ok(v) = s.parse::<i64>() {
        return Some(v);
    }
    let mut total = 0i64;
    let mut current = 0i64;
    for ch in s.chars() {
        match ch {
            '' => current = current.checked_add(1)?,
            '' => current = current.checked_add(2)?,
            '' => current = current.checked_add(3)?,
            '' => current = current.checked_add(4)?,
            '' => current = current.checked_add(5)?,
            '' => current = current.checked_add(6)?,
            '' => current = current.checked_add(7)?,
            '' => current = current.checked_add(8)?,
            '' => current = current.checked_add(9)?,
            '' => {
                let lhs = if current == 0 { 1 } else { current };
                total = total.checked_add(lhs.checked_mul(10)?)?;
                current = 0;
            }
            '' => {
                let lhs = if current == 0 { 1 } else { current };
                total = total.checked_add(lhs.checked_mul(100)?)?;
                current = 0;
            }
            '' => {
                let lhs = if current == 0 { 1 } else { current };
                total = total.checked_add(lhs.checked_mul(1000)?)?;
                current = 0;
            }
            _ => return None,
        }
    }
    total.checked_add(current)
}

pub fn rules() -> Vec<Rule> {
    vec![Rule {
        name: "ordinal (ja 第...)".to_string(),
        pattern: vec![regex("第([0-9一二三四五六七八九十百千]+)")],
        production: Box::new(|nodes| {
            let s = match &nodes[0].token_data {
                TokenData::RegexMatch(m) => m.group(1)?,
                _ => return None,
            };
            Some(TokenData::Ordinal(OrdinalData::new(parse_ja_numeral(s)?)))
        }),
    }]
}