1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
mod tests;

pub fn chars_to_num(s: &[char]) -> Option<i64> {
    match s {
        ['無'] => Some(0),
        ['下', tail @ ..] => positive(tail).map(|a| -a),
        simple => positive(simple),
    }
}

pub fn str_to_num(s: &str) -> Option<i64> {
    chars_to_num(&s.chars().collect::<Vec<_>>())
}

fn less_than_10(s: char) -> Option<i64> {
    match s {
        '一' => Some(1),
        '二' => Some(2),
        '三' => Some(3),
        '四' => Some(4),
        '五' => Some(5),
        '六' => Some(6),
        '七' => Some(7),
        '八' => Some(8),
        '九' => Some(9),
        _ => None,
    }
}

fn less_than_100(s: &[char]) -> Option<i64> {
    match s {
        ['十'] => Some(10),
        [digit] => less_than_10(*digit),
        [digit, '十'] => less_than_10(*digit).map(|a| a * 10),
        ['十', digit] => less_than_10(*digit).map(|a| a + 10),
        [digit1, '十', digit2] => {
            let d1 = less_than_10(*digit1)?;
            let d2 = less_than_10(*digit2)?;
            Some(d1 * 10 + d2)
        }
        _ => None,
    }
}

fn less_than_100_nun1_elided(s: &[char]) -> Option<i64> {
    match s {
        ['十'] => Some(10),
        [digit] => less_than_10(*digit),
        [digit, '十'] => less_than_10(*digit).map(|a| a * 10),
        ['十', digit] => less_than_10(*digit).map(|a| a + 10),
        [digit1, digit2] => {
            let d1 = less_than_10(*digit1)?;
            let d2 = less_than_10(*digit2)?;
            Some(d1 * 10 + d2)
        }
        _ => None,
    }
}

#[allow(clippy::many_single_char_names)]
fn less_than_10000_0000(input: &[char]) -> Option<i64> {
    match input {
        ['万'] => Some(10000),
        [head @ .., '万'] => less_than_10000_or_elided(head).map(|w| w * 10000),
        ['万', tail @ ..] => Some(10000 + less_than_10000_or_elided(tail)?),

        [a, '万', tail @ ..] => {
            Some(less_than_10000_or_elided(&[*a])? * 10000 + less_than_10000_or_elided(tail)?)
        }
        [a, b, '万', tail @ ..] => {
            Some(less_than_10000_or_elided(&[*a, *b])? * 10000 + less_than_10000_or_elided(tail)?)
        }
        [a, b, c, '万', tail @ ..] => Some(
            less_than_10000_or_elided(&[*a, *b, *c])? * 10000 + less_than_10000_or_elided(tail)?,
        ),
        [a, b, c, d, '万', tail @ ..] => Some(
            less_than_10000_or_elided(&[*a, *b, *c, *d])? * 10000
                + less_than_10000_or_elided(tail)?,
        ),
        [a, b, c, d, e, '万', tail @ ..] => Some(
            less_than_10000_or_elided(&[*a, *b, *c, *d, *e])? * 10000
                + less_than_10000_or_elided(tail)?,
        ),
        _ => less_than_10000(input),
    }
}

pub fn less_than_10000_or_elided(s: &[char]) -> Option<i64> {
    match less_than_100_nun1_elided(s) {
        Some(n) => Some(n),
        None => less_than_10000(s),
    }
}

pub fn less_than_10000_0000_or_elided(s: &[char]) -> Option<i64> {
    match less_than_100_nun1_elided(s) {
        Some(n) => Some(n),
        None => less_than_10000_0000(s),
    }
}

pub fn less_than_10000(s: &[char]) -> Option<i64> {
    match s {
        ['百'] => Some(100),
        [a, '百'] => less_than_100_nun1_elided(&[*a]).map(|w| w * 100),
        [a, b, '百'] => less_than_100_nun1_elided(&[*a, *b]).map(|w| w * 100),

        ['百', c] => less_than_100_nun1_elided(&[*c]).map(|a| 100 + a),
        ['百', c, d] => less_than_100_nun1_elided(&[*c, *d]).map(|a| 100 + a),
        ['百', c, d, e] => less_than_100(&[*c, *d, *e]).map(|a| 100 + a), // only for pure hundred
        [a, '百', tail @ ..] => {
            Some(less_than_100_nun1_elided(&[*a])? * 100 + less_than_100_nun1_elided(tail)?)
        }
        [a, b, '百', tail @ ..] => {
            Some(less_than_100_nun1_elided(&[*a, *b])? * 100 + less_than_100_nun1_elided(tail)?)
        }
        _ => less_than_100(s),
    }
}

fn positive(s: &[char]) -> Option<i64> {
    match s {
        ['億'] => Some(1_0000_0000),
        [head @ .., '億'] => less_than_10000_0000_or_elided(head).map(|w| w * 1_0000_0000),
        ['億', tail @ ..] => Some(1_0000_0000 + less_than_10000_0000_or_elided(tail)?),

        [a, '億', tail @ ..] => Some(
            less_than_10000_0000_or_elided(&[*a])? * 1_0000_0000
                + less_than_10000_0000_or_elided(tail)?,
        ),
        [a, b, '億', tail @ ..] => Some(
            less_than_10000_0000_or_elided(&[*a, *b])? * 1_0000_0000
                + less_than_10000_0000_or_elided(tail)?,
        ),
        [a, b, c, '億', tail @ ..] => Some(
            less_than_10000_0000_or_elided(&[*a, *b, *c])? * 1_0000_0000
                + less_than_10000_0000_or_elided(tail)?,
        ),
        // only need to handle till 21億
        _ => less_than_10000_0000(s),
    }
}