Skip to main content

terbilang/
lib.rs

1struct ValueLabel {
2    value: i64,
3    label: &'static str,
4}
5
6// HARUS diurutkan dari yang terbesar ke yang terkecil
7static DENOMINASI: [ValueLabel; 6] = [
8    ValueLabel {
9        value: 1_000_000_000_000,
10        label: "triliun",
11    },
12    ValueLabel {
13        value: 1_000_000_000,
14        label: "milyar",
15    },
16    ValueLabel {
17        value: 1_000_000,
18        label: "juta",
19    },
20    ValueLabel {
21        value: 1_000,
22        label: "ribu",
23    },
24    ValueLabel {
25        value: 100,
26        label: "ratus",
27    },
28    ValueLabel {
29        value: 10,
30        label: "puluh",
31    },
32];
33
34static SATUAN: [ValueLabel; 12] = [
35    ValueLabel {
36        value: 0,
37        label: "nol",
38    },
39    ValueLabel {
40        value: 1,
41        label: "satu",
42    },
43    ValueLabel {
44        value: 2,
45        label: "dua",
46    },
47    ValueLabel {
48        value: 3,
49        label: "tiga",
50    },
51    ValueLabel {
52        value: 4,
53        label: "empat",
54    },
55    ValueLabel {
56        value: 5,
57        label: "lima",
58    },
59    ValueLabel {
60        value: 6,
61        label: "enam",
62    },
63    ValueLabel {
64        value: 7,
65        label: "tujuh",
66    },
67    ValueLabel {
68        value: 8,
69        label: "delapan",
70    },
71    ValueLabel {
72        value: 9,
73        label: "sembilan",
74    },
75    ValueLabel {
76        value: 10,
77        label: "sepuluh",
78    },
79    ValueLabel {
80        value: 11,
81        label: "sebelas",
82    },
83];
84
85fn satuan(number: i64) -> String {
86    if let Some(n) = SATUAN.iter().find(|x| x.value == number) {
87        String::from(n.label)
88    } else {
89        "".to_string() // should be impossible
90    }
91}
92
93fn belasan(number: i64) -> String {
94    format!("{} belas", terbilang_helper(number % 10))
95}
96
97fn other(number: i64) -> String {
98    if let Some(denom) = DENOMINASI.iter().find(|x| number >= x.value) {
99        let s = format!(
100            "{} {}",
101            terbilang_helper(number / denom.value),
102            denom.label
103        );
104        let s = if number % denom.value == 0 {
105            s
106        } else {
107            format!("{} {}", s, terbilang_helper(number % denom.value))
108        };
109        s.replace("satu ratus", "seratus")
110            .replace("satu ribu", "seribu")
111    } else {
112        "".to_string() // should be impossible
113    }
114}
115
116fn terbilang_helper(number: i64) -> String {
117    match number {
118        0..=11 => satuan(number),
119        12..=19 => belasan(number),
120        _ => other(number),
121    }
122}
123
124/// Returns said number (terbilang) in Indonesia Language (Bahasa Indonesia).
125///
126/// # Examples
127///
128/// ```
129/// use terbilang::terbilang;
130/// let said = terbilang(10);
131/// ```
132pub fn terbilang(number: i64) -> String {
133    let s = terbilang_helper(number.abs());
134    if number < 0 {
135        format!("negatif {}", s)
136    } else {
137        s
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn terbilang_it_works() {
147        let tests = [
148            (-1_123_456_789_123, "negatif satu triliun seratus dua puluh tiga milyar empat ratus lima puluh enam juta tujuh ratus delapan puluh sembilan ribu seratus dua puluh tiga"),
149            (-1_000, "negatif seribu"),
150            (0, "nol"),
151            (1, "satu"),
152            (2, "dua"),
153            (3, "tiga"),
154            (4, "empat"),
155            (5, "lima"),
156            (6, "enam"),
157            (7, "tujuh"),
158            (8, "delapan"),
159            (9, "sembilan"),
160            (10, "sepuluh"),
161            (11, "sebelas"),
162            (12, "dua belas"),
163            (13, "tiga belas"),
164            (14, "empat belas"),
165            (15, "lima belas"),
166            (16, "enam belas"),
167            (17, "tujuh belas"),
168            (18, "delapan belas"),
169            (19, "sembilan belas"),
170            (20, "dua puluh"),
171            (29, "dua puluh sembilan"),
172            (99, "sembilan puluh sembilan"),
173            (100, "seratus"),
174            (110, "seratus sepuluh"),
175            (111, "seratus sebelas"),
176            (119, "seratus sembilan belas"),
177            (220, "dua ratus dua puluh"),
178            (1000, "seribu"),
179            (1019, "seribu sembilan belas"),
180            (1119, "seribu seratus sembilan belas"),
181            (2210, "dua ribu dua ratus sepuluh"),
182            (2220, "dua ribu dua ratus dua puluh"),
183            (10000, "sepuluh ribu"),
184            (12220, "dua belas ribu dua ratus dua puluh"),
185            (22220, "dua puluh dua ribu dua ratus dua puluh"),
186            (222220, "dua ratus dua puluh dua ribu dua ratus dua puluh"),
187            (2222220, "dua juta dua ratus dua puluh dua ribu dua ratus dua puluh"),
188            (22222220, "dua puluh dua juta dua ratus dua puluh dua ribu dua ratus dua puluh"),
189            (222222220, "dua ratus dua puluh dua juta dua ratus dua puluh dua ribu dua ratus dua puluh"),
190            (987654321, "sembilan ratus delapan puluh tujuh juta enam ratus lima puluh empat ribu tiga ratus dua puluh satu"),
191            (1234567890, "satu milyar dua ratus tiga puluh empat juta lima ratus enam puluh tujuh ribu delapan ratus sembilan puluh"),
192            (2222222220, "dua milyar dua ratus dua puluh dua juta dua ratus dua puluh dua ribu dua ratus dua puluh"),
193            (1231234567890, "satu triliun dua ratus tiga puluh satu milyar dua ratus tiga puluh empat juta lima ratus enam puluh tujuh ribu delapan ratus sembilan puluh"),
194            (451231234567890, "empat ratus lima puluh satu triliun dua ratus tiga puluh satu milyar dua ratus tiga puluh empat juta lima ratus enam puluh tujuh ribu delapan ratus sembilan puluh"),
195            (4561231234567890, "empat ribu lima ratus enam puluh satu triliun dua ratus tiga puluh satu milyar dua ratus tiga puluh empat juta lima ratus enam puluh tujuh ribu delapan ratus sembilan puluh"),
196            ];
197
198        for test in tests.iter() {
199            assert_eq!(terbilang(test.0), String::from(test.1));
200        }
201    }
202}