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
use pomsky_macro::pomsky;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use lazy_static::lazy_static;
use regex::Regex;
pub mod english;
pub mod latin;
pub mod util;
pub type LanguageOptions = HashMap<String, String>;
pub type ToWordsReturn = Result<String, ToWordsError>;
pub type LanguagesMap =
HashMap<String, fn(&str, &LanguageOptions) -> ToWordsReturn>;
lazy_static! {
static ref IS_NUMBER_REGEX: Regex = Regex::new(
pomsky! { ^ "-"? (([d]+ "."?) | ("." [d]+) | ([d]+ "." [d]+)) $ }
)
.unwrap();
}
#[derive(Serialize, Deserialize)]
pub struct ToWordsOptions {
pub language: String,
}
#[derive(Serialize, Deserialize)]
pub enum ToWordsError {
NotANumber,
UnimplementedLanguage,
}
fn add_default_languages(languages: &mut LanguagesMap) {
if !languages.contains_key("en") {
languages.insert("en".to_string(), english::to_words);
}
if !languages.contains_key("la") {
languages.insert("la".to_string(), latin::to_words);
}
}
pub fn to_words(
number: &str,
options: &ToWordsOptions,
language_options: &LanguageOptions,
languages: &mut LanguagesMap,
) -> Result<String, ToWordsError> {
if !IS_NUMBER_REGEX.is_match(number) {
return Err(ToWordsError::NotANumber);
}
add_default_languages(languages);
let mut parsed_number = number
.trim_start_matches('-')
.trim_start_matches('0')
.to_string();
if parsed_number.starts_with('.') {
parsed_number = format!("0{}", parsed_number);
}
if parsed_number.len() == 0 {
parsed_number = "0".to_string();
}
if number.starts_with('-') {
parsed_number = format!("-{}", parsed_number);
}
if parsed_number.contains('.') {
parsed_number = parsed_number.trim_end_matches('0').to_string();
if parsed_number.ends_with('.') {
parsed_number.pop();
}
}
match languages.get(&options.language) {
Some(language) => (language)(&parsed_number, language_options),
None => Err(ToWordsError::UnimplementedLanguage),
}
}