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::NumeralData;

fn zero_to_ten(s: &str) -> Option<f64> {
    match s {
        "ສູນ" => Some(0.0),
        "ໜຶ່ງ" => Some(1.0),
        "ສອງ" => Some(2.0),
        "ສາມ" => Some(3.0),
        "ສີ່" => Some(4.0),
        "ຫ້າ" => Some(5.0),
        "ຫົກ" => Some(6.0),
        "ເຈັດ" => Some(7.0),
        "ແປດ" => Some(8.0),
        "ເກົ້າ" => Some(9.0),
        "ສິບ" => Some(10.0),
        _ => None,
    }
}

fn eleven_to_nineteen(s: &str) -> Option<f64> {
    match s {
        "ສິບເອັດ" => Some(11.0),
        "ສິບສອງ" => Some(12.0),
        "ສິບສາມ" => Some(13.0),
        "ສິບສີ່" => Some(14.0),
        "ສິບຫ້າ" => Some(15.0),
        "ສິບຫົກ" => Some(16.0),
        "ສິບເຈັດ" => Some(17.0),
        "ສິບແປດ" => Some(18.0),
        "ສິບເກົ້າ" => Some(19.0),
        _ => None,
    }
}

fn twenty_to_ninety(s: &str) -> Option<f64> {
    match s {
        "ຊາວ" => Some(20.0),
        "ສາມສິບ" => Some(30.0),
        "ສິບສີ່" => Some(40.0),
        "ຫ້າສິບ" => Some(50.0),
        "ຫົກສິບ" => Some(60.0),
        "ເຈັດສິບ" => Some(70.0),
        "ແປດສິບ" => Some(80.0),
        "ເກົ້າສິບ" => Some(90.0),
        _ => None,
    }
}

fn twenty_ones(s: &str) -> Option<f64> {
    match s {
        "ຊາວເອັດ" => Some(21.0),
        "ຊາວສອງ" => Some(22.0),
        "ຊາວສາມ" => Some(23.0),
        "ຊາວສີ່" => Some(24.0),
        "ຊາວຫ້າ" => Some(25.0),
        "ຊາວຫົກ" => Some(26.0),
        "ຊາວເຈັດ" => Some(27.0),
        "ຊາວແປດ" => Some(28.0),
        "ຊາວເກົ້າ" => Some(29.0),
        _ => None,
    }
}

pub fn rules() -> Vec<Rule> {
    vec![
        Rule {
            name: "number (0..10)".to_string(),
            pattern: vec![regex("(ສູນ|ໜຶ່ງ|ສອງ|ສາມ|ສີ່|ຫ້າ|ຫົກ|ເຈັດ|ແປດ|ເກົ້າ|ສິບ)")],
            production: Box::new(|nodes| {
                let s = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m.group(1)?,
                    _ => return None,
                };
                Some(TokenData::Numeral(NumeralData::new(zero_to_ten(s)?)))
            }),
        },
        Rule {
            name: "number (11..19)".to_string(),
            pattern: vec![regex("(ສິບເອັດ|ສິບສອງ|ສິບສາມ|ສິບສີ່|ສິບຫ້າ|ສິບຫົກ|ສິບເຈັດ|ສິບແປດ|ສິບເກົ້າ)")],
            production: Box::new(|nodes| {
                let s = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m.group(1)?,
                    _ => return None,
                };
                Some(TokenData::Numeral(NumeralData::new(eleven_to_nineteen(s)?)))
            }),
        },
        Rule {
            name: "number (21..29)".to_string(),
            pattern: vec![regex(
                "(ຊາວເອັດ|ຊາວສອງ|ຊາວສາມ|ຊາວສີ່|ຊາວຫ້າ|ຊາວຫົກ|ຊາວເຈັດ|ຊາວແປດ|ຊາວເກົ້າ)",
            )],
            production: Box::new(|nodes| {
                let s = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m.group(1)?,
                    _ => return None,
                };
                Some(TokenData::Numeral(NumeralData::new(twenty_ones(s)?)))
            }),
        },
        Rule {
            name: "integer (20..90)".to_string(),
            pattern: vec![regex("(ຊາວ|ສາມສິບ|ສິບສີ່|ຫ້າສິບ|ຫົກສິບ|ເຈັດສິບ|ແປດສິບ|ເກົ້າສິບ)")],
            production: Box::new(|nodes| {
                let s = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m.group(1)?,
                    _ => return None,
                };
                Some(TokenData::Numeral(NumeralData::new(twenty_to_ninety(s)?)))
            }),
        },
        Rule {
            name: "integer ([3-9][1-9])".to_string(),
            pattern: vec![regex(
                "(ສາມສິບ|ສິບສີ່|ຫ້າສິບ|ຫົກສິບ|ເຈັດສິບ|ແປດສິບ|ເກົ້າສິບ)(ໜຶ່ງ|ສອງ|ສາມ|ສີ່|ຫ້າ|ຫົກ|ເຈັດ|ແປດ|ເກົ້າ)",
            )],
            production: Box::new(|nodes| {
                let m = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m,
                    _ => return None,
                };
                let t = m.group(1)?;
                let u = m.group(2)?;
                Some(TokenData::Numeral(NumeralData::new(
                    twenty_to_ninety(t)? + zero_to_ten(u)?,
                )))
            }),
        },
    ]
}