1use once_cell::sync::Lazy;
4use std::collections::HashMap;
5
6use crate::jmath;
7
8pub fn spell_number(n: u32) -> String {
24 assert!(n <= 1000);
25
26 let digits = jmath::digits(n as u64);
27 match digits.len() {
28 1 => length_1(&digits),
29 2 => length_2(&digits),
30 3 => length_3(&digits),
31 4 => length_4(&digits),
32 _ => String::from("unknown"),
33 }
34}
35
36static NUMBERS: Lazy<HashMap<i32, &str>> = Lazy::new(|| {
41 HashMap::from([
42 (0, "zero"),
43 (1, "one"),
44 (2, "two"),
45 (3, "three"),
46 (4, "four"),
47 (5, "five"),
48 (6, "six"),
49 (7, "seven"),
50 (8, "eight"),
51 (9, "nine"),
52 (10, "ten"),
53 (11, "eleven"),
54 (12, "twelve"),
55 (13, "thirteen"),
56 (14, "fourteen"),
57 (15, "fifteen"),
58 (16, "sixteen"),
59 (17, "seventeen"),
60 (18, "eighteen"),
61 (19, "nineteen"),
62 (20, "twenty"),
63 (30, "thirty"),
64 (40, "forty"),
65 (50, "fifty"),
66 (60, "sixty"),
67 (70, "seventy"),
68 (80, "eighty"),
69 (90, "ninety"),
70 (100, "one hundred"),
71 (1000, "one thousand"),
72 ])
73});
74
75fn length_1(digits: &[i32]) -> String {
76 NUMBERS.get(&digits[0]).unwrap().to_string()
77}
78
79fn length_2(digits: &[i32]) -> String {
80 let n = digits[0] * 10 + digits[1];
81 if digits[0] == 1 {
82 NUMBERS.get(&n).unwrap().to_string()
83 } else {
84 if digits[1] == 0 {
85 return NUMBERS.get(&n).unwrap().to_string();
86 }
87 let n = digits[0] * 10;
89 format!(
90 "{}-{}",
91 NUMBERS.get(&n).unwrap(),
92 NUMBERS.get(&digits[1]).unwrap()
93 )
94 }
95}
96
97fn length_3(digits: &[i32]) -> String {
98 let head = digits[0];
99 let tail = digits[1] * 10 + digits[2];
100 if tail == 0 {
101 format!("{} hundred", length_1(&[head]))
103 } else if tail < 10 {
104 format!("{} hundred and {}", length_1(&[head]), length_1(&[tail]))
106 } else {
107 let tail_digits = jmath::digits(tail as u64);
108 format!(
109 "{} hundred and {}",
110 length_1(&[head]),
111 length_2(&tail_digits)
112 )
113 }
114}
115
116fn length_4(digits: &[i32]) -> String {
117 let n = digits[0] * 1000 + digits[1] * 100 + digits[2] * 10 + digits[3];
118 NUMBERS.get(&n).unwrap().to_string()
119}
120
121#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn spell_number_test1() {
129 assert_eq!(spell_number(0), "zero");
130 assert_eq!(spell_number(0), "zero");
131 assert_eq!(spell_number(1), "one");
132 assert_eq!(spell_number(2), "two");
133 assert_eq!(spell_number(3), "three");
134 assert_eq!(spell_number(4), "four");
135 assert_eq!(spell_number(5), "five");
136 assert_eq!(spell_number(6), "six");
137 assert_eq!(spell_number(7), "seven");
138 assert_eq!(spell_number(8), "eight");
139 assert_eq!(spell_number(9), "nine");
140 assert_eq!(spell_number(10), "ten");
141 assert_eq!(spell_number(11), "eleven");
142 assert_eq!(spell_number(12), "twelve");
143 assert_eq!(spell_number(13), "thirteen");
144 assert_eq!(spell_number(14), "fourteen");
145 assert_eq!(spell_number(15), "fifteen");
146 assert_eq!(spell_number(16), "sixteen");
147 assert_eq!(spell_number(17), "seventeen");
148 assert_eq!(spell_number(18), "eighteen");
149 assert_eq!(spell_number(19), "nineteen");
150 assert_eq!(spell_number(20), "twenty");
151 assert_eq!(spell_number(30), "thirty");
152 assert_eq!(spell_number(40), "forty");
153 assert_eq!(spell_number(50), "fifty");
154 assert_eq!(spell_number(60), "sixty");
155 assert_eq!(spell_number(70), "seventy");
156 assert_eq!(spell_number(80), "eighty");
157 assert_eq!(spell_number(90), "ninety");
158 assert_eq!(spell_number(100), "one hundred");
159 assert_eq!(spell_number(1000), "one thousand");
160 assert_eq!(spell_number(115), "one hundred and fifteen");
162 assert_eq!(spell_number(342), "three hundred and forty-two");
163 }
164
165 #[test]
166 fn spell_number_test2() {
167 let mut sb = String::new();
168 for n in 1..1000 + 1 {
169 sb.push_str(&spell_number(n));
170 }
171 sb = sb.replace(" ", "").replace("-", "");
172 assert_eq!(sb.len(), 21124);
173 }
174}