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 bengali_digit_to_ascii(c: char) -> char {
    match c {
        '' => '0',
        '' => '1',
        '' => '2',
        '' => '3',
        '' => '4',
        '' => '5',
        '' => '6',
        '' => '7',
        '' => '8',
        '' => '9',
        _ => c,
    }
}

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: "bengali forms".to_string(),
            pattern: vec![regex("([০১২৩৪৫৬৭৮৯]{1,18})")],
            production: Box::new(|nodes| {
                let s = match &nodes[0].token_data {
                    TokenData::RegexMatch(m) => m.group(1)?,
                    _ => return None,
                };
                let ascii: String = s.chars().map(bengali_digit_to_ascii).collect();
                Some(TokenData::Numeral(NumeralData::new(ascii.parse().ok()?)))
            }),
        },
        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)?)))
            }),
        },
    ]
}