1#[derive(Copy, Clone)]
7pub enum ScaleType {
8 Short,
9 Long
10}
11
12struct NamedNumber {
13 number: u128,
14 singular_name: &'static str,
15 plural_name: &'static str
16}
17
18impl NamedNumber {
19
20 pub fn new(number: u128, singular_name: &'static str, plural_name: &'static str) -> NamedNumber {
21 NamedNumber { number, singular_name, plural_name }
22 }
23}
24
25pub struct NumberToSpanish {
26 scale: Vec<NamedNumber>
27}
28
29impl NumberToSpanish {
30
31 pub fn new(scale_type: ScaleType) -> NumberToSpanish {
32 let scale = Self::get_scale(scale_type);
33 NumberToSpanish { scale }
34 }
35
36 fn get_scale(scale_type: ScaleType) -> Vec<NamedNumber> {
37 match scale_type {
38 ScaleType::Short => vec![
39 NamedNumber::new(1000000000000000000000000000000000000, "undecillón", "undecillones"),
40 NamedNumber::new(1000000000000000000000000000000000, "decillón", "decillones"),
41 NamedNumber::new(1000000000000000000000000000000, "nonillón", "nonillones"),
42 NamedNumber::new(1000000000000000000000000000, "octillón", "octillones"),
43 NamedNumber::new(1000000000000000000000000, "septillón", "septillones"),
44 NamedNumber::new(1000000000000000000000, "sextillón", "sextillones"),
45 NamedNumber::new(1000000000000000000, "quintillón", "quintillones"),
46 NamedNumber::new(1000000000000000, "cuatrillón", "cuatrillones"),
47 NamedNumber::new(1000000000000, "trillón", "trillones"),
48 NamedNumber::new(1000000000, "billón", "billones"),
49 NamedNumber::new(1000000, "millón", "millones"),
50 NamedNumber::new(1, "", "")
51 ],
52 ScaleType::Long => vec![
53 NamedNumber::new(1000000000000000000000000000000000000, "sextillón", "sextillones"),
54 NamedNumber::new(1000000000000000000000000000000, "quintillón", "quintillones"),
55 NamedNumber::new(1000000000000000000000000, "cuatrillón", "cuatrillones"),
56 NamedNumber::new(1000000000000000000, "trillón", "trillones"),
57 NamedNumber::new(1000000000000, "billón", "billones"),
58 NamedNumber::new(1000000, "millón", "millones"),
59 NamedNumber::new(1, "", "")
60 ]
61 }
62 }
63
64 pub fn number_to_spanish(&self, number: u128, separator: &str) -> String {
65 match number {
66 0 => "cero".to_owned(),
67 _ => self.translate_positive_number(number).join(separator)
68 }
69 }
70
71 fn translate_positive_number(&self, number: u128) -> Vec<String> {
72 let mut translations = vec![];
73 let mut translation = String::from("");
74
75 let (divisor, divisor_name) = self.get_greatest_divisor(number);
76 let fst_num = number / divisor;
77 let snd_num = number % divisor;
78
79 if fst_num > 0 {
80 let is_not_end_of_sentence = snd_num > 0 || divisor > 1;
81 let fst_num_translation = Self::translate_1_until_million(fst_num, is_not_end_of_sentence);
82 translation.push_str(&fst_num_translation);
83 }
84 if translation.len() > 0 {
85 if divisor_name.len() > 0 {
86 translation.push(' ');
87 translation.push_str(&divisor_name);
88 }
89 translations.push(translation);
90 }
91 if snd_num > 0 {
92 translations.extend(self.translate_positive_number(snd_num));
93 }
94 translations
95 }
96
97 fn get_greatest_divisor(&self, number: u128) -> (u128, String) {
98 let divisor = self.scale.iter().find(|d| d.number <= number).unwrap();
99 let v = number / divisor.number;
100 let divisor_name = if v > 1 { divisor.plural_name } else { divisor.singular_name };
101 (divisor.number, divisor_name.to_owned())
102 }
103
104 fn translate_1_until_million(number: u128, is_not_end: bool) -> String {
105 match number {
106 1...999 => Self::translate_1_to_999(number, is_not_end),
107 1000...999999 => Self::translate_1000_until_million(number, is_not_end),
108 _ => panic!("number {}", number)
109 }
110 }
111
112 fn translate_1_to_999(number: u128, is_not_end: bool) -> String {
113 match number {
114 1...99 => Self::translate_1_to_99(number, is_not_end),
115 100 => "cien".to_owned(),
116 101...999 => Self::translate_101_to_999(number, is_not_end),
117 _ => panic!("number {}", number)
118 }
119 }
120
121 fn translate_1000_until_million(number: u128, is_not_end: bool) -> String {
122 let fst_num = number / 1000;
123 let snd_digit = number % 1000;
124 let mut translation = String::from("");
125 if fst_num > 1 {
126 translation.push_str(&Self::translate_1_to_999(fst_num, is_not_end || snd_digit > 0));
127 translation.push(' ');
128 }
129 translation.push_str("mil");
130 if snd_digit > 0 {
131 translation.push(' ');
132 translation.push_str(&Self::translate_1_to_999(snd_digit, is_not_end));
133 }
134 translation
135 }
136
137 fn translate_1_to_99(number: u128, is_not_end: bool) -> String {
138 match number {
139 1...30 => Self::translate_from_1_to_30(number, is_not_end),
140 31...99 => Self::translate_31_to_99(number, is_not_end),
141 _ => panic!("number {}", number)
142 }
143 }
144
145 fn translate_101_to_999(number: u128, is_not_end: bool) -> String {
146 let fst_digit = number / 100;
147 let snd_digit = number % 100;
148 let mut translation = Self::match_multiples_of_100_to_900(fst_digit);
149 if snd_digit > 0 {
150 translation.push(' ');
151 translation.push_str(&Self::translate_1_to_99(snd_digit, is_not_end));
152 }
153 translation
154 }
155
156 fn translate_from_1_to_30(number: u128, is_not_end: bool) -> String {
157 (match number {
158 n if n == 1 && is_not_end => "un",
159 1 => "uno",
160 2 => "dos",
161 3 => "tres",
162 4 => "cuatro",
163 5 => "cinco",
164 6 => "seis",
165 7 => "siete",
166 8 => "ocho",
167 9 => "nueve",
168 10 => "diez",
169 11 => "once",
170 12 => "doce",
171 13 => "trece",
172 14 => "catorce",
173 15 => "quince",
174 16 => "dieciséis",
175 17 => "diecisiete",
176 18 => "dieciocho",
177 19 => "diecinueve",
178 20 => "veinte",
179 21 => "veintiuno",
180 22 => "veintidós",
181 23 => "veintitrés",
182 24 => "venticuatro",
183 25 => "veinticinco",
184 26 => "veintiséis",
185 27 => "veintisiete",
186 28 => "veintiocho",
187 29 => "veintinueve",
188 30 => "treinta",
189 _ => panic!("number {}", number)
190 }).to_owned()
191 }
192
193 fn translate_31_to_99(number: u128, is_not_end: bool) -> String {
194 let fst_digit = number / 10;
195 let snd_digit = number % 10;
196 let mut translation = Self::match_multiples_of_10_to_90(fst_digit);
197 if snd_digit > 0 {
198 translation.push_str(" y ");
199 translation.push_str(&Self::translate_from_1_to_30(snd_digit, is_not_end));
200 }
201 translation
202 }
203
204 fn match_multiples_of_10_to_90(number: u128) -> String {
205 (match number {
206 1 => "diez",
207 2 => "veinte",
208 3 => "treinta",
209 4 => "cuarenta",
210 5 => "cincuenta",
211 6 => "sesenta",
212 7 => "setenta",
213 8 => "ochenta",
214 9 => "noventa",
215 _ => panic!("number {}", number)
216 }).to_owned()
217 }
218
219 fn match_multiples_of_100_to_900(number: u128) -> String {
220 (match number {
221 1 => "ciento",
222 2 => "doscientos",
223 3 => "trescientos",
224 4 => "cuatrocientos",
225 5 => "quinientos",
226 6 => "seiscientos",
227 7 => "setecientos",
228 8 => "ochocientos",
229 9 => "novecientos",
230 _ => panic!("number {}", number)
231 }).to_owned()
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn it_works() {
241 let nsl = NumberToSpanish::new(ScaleType::Long);
242 let nss = NumberToSpanish::new(ScaleType::Short);
243
244 assert_eq!(nsl.number_to_spanish(1, " "), "uno");
245 assert_eq!(nss.number_to_spanish(1, " "), "uno");
246 assert_eq!(nsl.number_to_spanish(1000, " "), "mil");
247 assert_eq!(nss.number_to_spanish(1000, " "), "mil");
248 assert_eq!(nsl.number_to_spanish(1000000, " "), "un millón");
249 assert_eq!(nss.number_to_spanish(1000000, " "), "un millón");
250 assert_eq!(nsl.number_to_spanish(1000000000, " "), "mil millones");
251 assert_eq!(nss.number_to_spanish(1000000000, " "), "un billón");
252 assert_eq!(nsl.number_to_spanish(1000000000000, " "), "un billón");
253 assert_eq!(nss.number_to_spanish(1000000000000, " "), "un trillón");
254 assert_eq!(nsl.number_to_spanish(1000000000000000, " "), "mil billones");
255 assert_eq!(nss.number_to_spanish(1000000000000000, " "), "un cuatrillón");
256 assert_eq!(nsl.number_to_spanish(1000000000000000000, " "), "un trillón");
257 assert_eq!(nss.number_to_spanish(1000000000000000000, " "), "un quintillón");
258 assert_eq!(nsl.number_to_spanish(1000000000000000000000, " "), "mil trillones");
259 assert_eq!(nss.number_to_spanish(1000000000000000000000, " "), "un sextillón");
260 assert_eq!(nsl.number_to_spanish(1000000000000000000000000, " "), "un cuatrillón");
261 assert_eq!(nss.number_to_spanish(1000000000000000000000000, " "), "un septillón");
262 assert_eq!(nsl.number_to_spanish(1000000000000000000000000000, " "), "mil cuatrillones");
263 assert_eq!(nss.number_to_spanish(1000000000000000000000000000, " "), "un octillón");
264 assert_eq!(nsl.number_to_spanish(1000000000000000000000000000000, " "), "un quintillón");
265 assert_eq!(nss.number_to_spanish(1000000000000000000000000000000, " "), "un nonillón");
266
267 assert_eq!(nsl.number_to_spanish(0, " "), "cero");
268 assert_eq!(nsl.number_to_spanish(7, " "), "siete");
269 assert_eq!(nsl.number_to_spanish(19, " "), "diecinueve");
270 assert_eq!(nsl.number_to_spanish(21, " "), "veintiuno");
271 assert_eq!(nsl.number_to_spanish(26, " "), "veintiséis");
272 assert_eq!(nsl.number_to_spanish(29, " "), "veintinueve");
273 assert_eq!(nsl.number_to_spanish(31, " "), "treinta y uno");
274 assert_eq!(nsl.number_to_spanish(40, " "), "cuarenta");
275 assert_eq!(nsl.number_to_spanish(56, " "), "cincuenta y seis");
276 assert_eq!(nsl.number_to_spanish(99, " "), "noventa y nueve");
277 assert_eq!(nsl.number_to_spanish(100, " "), "cien");
278 assert_eq!(nsl.number_to_spanish(101, " "), "ciento uno");
279 assert_eq!(nsl.number_to_spanish(120, " "), "ciento veinte");
280 assert_eq!(nsl.number_to_spanish(456, " "), "cuatrocientos cincuenta y seis");
281 assert_eq!(nsl.number_to_spanish(999, " "), "novecientos noventa y nueve");
282 assert_eq!(nsl.number_to_spanish(1000, " "), "mil");
283 assert_eq!(nsl.number_to_spanish(1001, " "), "mil uno");
284 assert_eq!(nsl.number_to_spanish(1456, " "), "mil cuatrocientos cincuenta y seis");
285 assert_eq!(nsl.number_to_spanish(2456, " "), "dos mil cuatrocientos cincuenta y seis");
286 assert_eq!(nsl.number_to_spanish(100000, " "), "cien mil");
287 assert_eq!(nsl.number_to_spanish(345456, " "), "trescientos cuarenta y cinco mil cuatrocientos cincuenta y seis");
288 assert_eq!(nsl.number_to_spanish(999999, " "), "novecientos noventa y nueve mil novecientos noventa y nueve");
289 assert_eq!(nsl.number_to_spanish(1000001, " "), "un millón uno");
290 assert_eq!(nsl.number_to_spanish(1200300400100, " "), "un billón doscientos mil trescientos millones cuatrocientos mil cien");
291 assert_eq!(nsl.number_to_spanish(12003004001000, " "), "doce billones tres mil cuatro millones mil");
292 assert_eq!(nsl.number_to_spanish(91928091829809, " "), "noventa y un billones novecientos veintiocho mil noventa y un millones ochocientos veintinueve mil ochocientos nueve");
293 assert_eq!(nsl.number_to_spanish(120030040010010, " "), "ciento veinte billones treinta mil cuarenta millones diez mil diez");
294 assert_eq!(nsl.number_to_spanish(120130340010410103, " "), "ciento veinte mil ciento treinta billones trescientos cuarenta mil diez millones cuatrocientos diez mil ciento tres");
295 assert_eq!(nsl.number_to_spanish(1201303400104101030, " "), "un trillón doscientos un mil trescientos tres billones cuatrocientos mil ciento cuatro millones ciento un mil treinta");
296 assert_eq!(nsl.number_to_spanish(1000000000000000000000000, " "), "un cuatrillón");
297 assert_eq!(nsl.number_to_spanish(1201303400104101035678987, " "), "un cuatrillón doscientos un mil trescientos tres trillones cuatrocientos mil ciento cuatro billones ciento un mil treinta y cinco millones seiscientos setenta y ocho mil novecientos ochenta y siete");
298 assert_eq!(nsl.number_to_spanish(1271313457184191135678987, " "), "un cuatrillón doscientos setenta y un mil trescientos trece trillones cuatrocientos cincuenta y siete mil ciento ochenta y cuatro billones ciento noventa y un mil ciento treinta y cinco millones seiscientos setenta y ocho mil novecientos ochenta y siete");
299 assert_eq!(nsl.number_to_spanish(193127131345718419113567898, " "), "ciento noventa y tres cuatrillones ciento veintisiete mil ciento treinta y un trillones trescientos cuarenta y cinco mil setecientos dieciocho billones cuatrocientos diecinueve mil ciento trece millones quinientos sesenta y siete mil ochocientos noventa y ocho");
300 assert_eq!(nsl.number_to_spanish(1931271313457184191135678980, " "), "mil novecientos treinta y un cuatrillones doscientos setenta y un mil trescientos trece trillones cuatrocientos cincuenta y siete mil ciento ochenta y cuatro billones ciento noventa y un mil ciento treinta y cinco millones seiscientos setenta y ocho mil novecientos ochenta");
301 assert_eq!(nsl.number_to_spanish(31415926535897932384626433832795, " "), "treinta y un quintillones cuatrocientos quince mil novecientos veintiséis cuatrillones quinientos treinta y cinco mil ochocientos noventa y siete trillones novecientos treinta y dos mil trescientos ochenta y cuatro billones seiscientos veintiséis mil cuatrocientos treinta y tres millones ochocientos treinta y dos mil setecientos noventa y cinco");
302
303 assert_eq!(nsl.number_to_spanish(31415926535897932384626433832795, ", "), "treinta y un quintillones, cuatrocientos quince mil novecientos veintiséis cuatrillones, quinientos treinta y cinco mil ochocientos noventa y siete trillones, novecientos treinta y dos mil trescientos ochenta y cuatro billones, seiscientos veintiséis mil cuatrocientos treinta y tres millones, ochocientos treinta y dos mil setecientos noventa y cinco");
304 assert_eq!(nss.number_to_spanish(31415926535897932384626433832795, ", "), "treinta y un nonillones, cuatrocientos quince octillones, novecientos veintiséis septillones, quinientos treinta y cinco sextillones, ochocientos noventa y siete quintillones, novecientos treinta y dos cuatrillones, trescientos ochenta y cuatro trillones, seiscientos veintiséis billones, cuatrocientos treinta y tres millones, ochocientos treinta y dos mil setecientos noventa y cinco");
305 }
306}