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 lookup_ordinal(s: &str) -> Option<i64> {
    match s.to_lowercase().as_str() {
        "første" => Some(1),
        "andre" => Some(2),
        "tredje" => Some(3),
        "fjerde" => Some(4),
        "femte" => Some(5),
        "sjette" => Some(6),
        "syvende" => Some(7),
        "åttende" => Some(8),
        "niende" => Some(9),
        "tiende" => Some(10),
        "ellevte" => Some(11),
        "tolvte" => Some(12),
        "trettende" => Some(13),
        "fjortende" => Some(14),
        "femtende" => Some(15),
        "sekstende" => Some(16),
        "syttende" => Some(17),
        "attende" => Some(18),
        "nittende" => Some(19),
        "tyvende" | "tjuende" => Some(20),
        "enogtjuende" | "enogtyvende" => Some(21),
        "toogtyvende" | "toogtjuende" => Some(22),
        "treogtyvende" | "treogtjuende" => Some(23),
        "fireogtjuende" | "fireogtyvende" => Some(24),
        "femogtyvende" | "femogtjuende" => Some(25),
        "seksogtjuende" | "seksogtyvende" => Some(26),
        "syvogtyvende" | "syvogtjuende" => Some(27),
        "åtteogtyvende" | "åtteogtjuende" => Some(28),
        "niogtyvende" | "niogtjuende" => Some(29),
        "tredefte" => Some(30),
        "enogtredefte" => Some(31),
        _ => None,
    }
}

pub fn rules() -> Vec<Rule> {
    vec![
        Rule {
            name: "ordinals (first..31st)".to_string(),
            pattern: vec![regex("(første|andre|tredje|fjerde|femtende|femte|sjette|syvende|åttende|niende|tiende|ellevte|tolvte|trettende|fjortende|sekstende|syttende|attende|nittende|tyvende|tjuende|enogtyvende|toogtyvende|treogtyvende|fireogtyvende|femogtyvende|seksogtyvende|syvogtyvende|åtteogtyvende|niogtyvende|enogtjuende|toogtjuende|treogtjuende|fireogtjuende|femogtjuende|seksogtjuende|syvogtjuende|åtteogtyvend|niogtjuende|tredefte|enogtredefte)")],
            production: Box::new(|nodes| {
                let s = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m.group(1)?,
                    _ => return None,
                };
                Some(TokenData::Ordinal(OrdinalData::new(lookup_ordinal(s)?)))
            }),
        },
        Rule {
            name: "ordinal (digits)".to_string(),
            pattern: vec![regex("0*(\\d+)(\\.|ste?)")],
            production: Box::new(|nodes| {
                let v: i64 = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m.group(1)?.parse().ok()?,
                    _ => return None,
                };
                Some(TokenData::Ordinal(OrdinalData::new(v)))
            }),
        },
    ]
}