nb2fr/
lib.rs

1//
2// Copyright (C) 2020 Sébastien Helleu <flashcode@flashtux.org>
3//
4// This file is part of nb2fr.
5//
6// Nb2fr is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 3 of the License, or
9// (at your option) any later version.
10//
11// Nb2fr is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with nb2fr.  If not, see <https://www.gnu.org/licenses/>.
18//
19
20/// Converts an integer to literal French text.
21///
22/// # Examples:
23///
24///     assert_eq!(nb2fr::nb2fr(0), "zéro");
25///     assert_eq!(nb2fr::nb2fr(-42), "moins quarante-deux");
26///     assert_eq!(nb2fr::nb2fr(123), "cent vingt-trois");
27///     assert_eq!(nb2fr::nb2fr(2_000_000_000), "deux milliards");
28pub fn nb2fr(number: i64) -> String {
29    let number_1_99 = [
30        "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf",
31        "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize",
32        "dix-sept", "dix-huit", "dix-neuf", "vingt", "vingt et un",
33        "vingt-deux", "vingt-trois", "vingt-quatre", "vingt-cinq", "vingt-six",
34        "vingt-sept", "vingt-huit", "vingt-neuf", "trente", "trente et un",
35        "trente-deux", "trente-trois", "trente-quatre", "trente-cinq",
36        "trente-six", "trente-sept", "trente-huit", "trente-neuf", "quarante",
37        "quarante et un", "quarante-deux", "quarante-trois", "quarante-quatre",
38        "quarante-cinq", "quarante-six", "quarante-sept", "quarante-huit",
39        "quarante-neuf", "cinquante", "cinquante et un", "cinquante-deux",
40        "cinquante-trois", "cinquante-quatre", "cinquante-cinq",
41        "cinquante-six", "cinquante-sept", "cinquante-huit", "cinquante-neuf",
42        "soixante", "soixante et un", "soixante-deux", "soixante-trois",
43        "soixante-quatre", "soixante-cinq", "soixante-six", "soixante-sept",
44        "soixante-huit", "soixante-neuf", "soixante-dix", "soixante et onze",
45        "soixante-douze", "soixante-treize", "soixante-quatorze",
46        "soixante-quinze", "soixante-seize", "soixante-dix-sept",
47        "soixante-dix-huit", "soixante-dix-neuf", "quatre-vingts",
48        "quatre-vingt-un", "quatre-vingt-deux", "quatre-vingt-trois",
49        "quatre-vingt-quatre", "quatre-vingt-cinq", "quatre-vingt-six",
50        "quatre-vingt-sept", "quatre-vingt-huit", "quatre-vingt-neuf",
51        "quatre-vingt-dix", "quatre-vingt-onze", "quatre-vingt-douze",
52        "quatre-vingt-treize", "quatre-vingt-quatorze", "quatre-vingt-quinze",
53        "quatre-vingt-seize", "quatre-vingt-dix-sept", "quatre-vingt-dix-huit",
54        "quatre-vingt-dix-neuf",
55    ];
56    let number_1000 = [
57        "mille", "million", "milliard", "billion", "billiard", "trillion",
58    ];
59    if number == 0 {
60        return String::from("zéro");
61    }
62    let mut result = String::new();
63    if number < 0 {
64        result.push_str("moins");
65    }
66    let mut str_number = number.to_string().replace("-", "");
67    let zeroes_to_add = (3 - (str_number.len() % 3)) % 3;
68    str_number.insert_str(0, &"0".repeat(zeroes_to_add));
69    let mut nb3 = ((str_number.len() / 3) - 1) as i64;
70    let mut index = 0;
71    while nb3 >= 0 {
72        let grp3 = &str_number[index..index + 3];
73        let num_grp3 = grp3.parse::<i64>().unwrap();
74        if num_grp3 > 0 {
75            if num_grp3 != 1 || nb3 != 1 {
76                if num_grp3 > 99 {
77                    if num_grp3 / 100 > 1 {
78                        if !result.is_empty() {
79                            result.push(' ');
80                        }
81                        let index_num = (num_grp3 / 100) - 1;
82                        result.push_str(number_1_99[index_num as usize]);
83                    }
84                    if !result.is_empty() {
85                        result.push(' ');
86                    }
87                    result.push_str("cent");
88                    if num_grp3 / 100 > 1 && num_grp3 % 100 == 0 {
89                        result.push('s')
90                    }
91                }
92                if num_grp3 % 100 != 0 {
93                    if !result.is_empty() {
94                        result.push(' ');
95                    }
96                    let index_num = (num_grp3 % 100) - 1;
97                    result.push_str(number_1_99[index_num as usize]);
98                }
99            }
100            if nb3 > 0 {
101                if !result.is_empty() {
102                    result.push(' ');
103                }
104                result.push_str(number_1000[(nb3 - 1) as usize]);
105                if num_grp3 > 1 && nb3 > 1 {
106                    result.push('s');
107                }
108            }
109        }
110        index += 3;
111        nb3 -= 1;
112    }
113    result
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_nb2fr() {
122        assert_eq!(nb2fr(0), "zéro");
123        assert_eq!(nb2fr(1), "un");
124        assert_eq!(nb2fr(5), "cinq");
125        assert_eq!(nb2fr(10), "dix");
126        assert_eq!(nb2fr(100), "cent");
127        assert_eq!(nb2fr(123), "cent vingt-trois");
128        assert_eq!(nb2fr(200), "deux cents");
129        assert_eq!(nb2fr(123_456_789),
130                   "cent vingt-trois millions \
131                    quatre cent cinquante-six mille \
132                    sept cent quatre-vingt-neuf");
133        assert_eq!(nb2fr(123_456_789_012),
134                   "cent vingt-trois milliards \
135                    quatre cent cinquante-six millions \
136                    sept cent quatre-vingt-neuf mille \
137                    douze");
138        assert_eq!(nb2fr(2_000), "deux mille");
139        assert_eq!(nb2fr(2_000_000), "deux millions");
140        assert_eq!(nb2fr(2_000_000_000), "deux milliards");
141        assert_eq!(nb2fr(2_000_000_000_000), "deux billions");
142        assert_eq!(nb2fr(2_000_000_000_000_000), "deux billiards");
143        assert_eq!(nb2fr(2_000_000_000_000_000_000), "deux trillions");
144        assert_eq!(nb2fr(i64::MIN), // -9_223_372_036_854_775_808
145                   "moins neuf trillions \
146                    deux cent vingt-trois billiards \
147                    trois cent soixante-douze billions \
148                    trente-six milliards \
149                    huit cent cinquante-quatre millions \
150                    sept cent soixante-quinze mille \
151                    huit cent huit");
152        assert_eq!(nb2fr(i64::MAX), // 9_223_372_036_854_775_807
153                   "neuf trillions \
154                    deux cent vingt-trois billiards \
155                    trois cent soixante-douze billions \
156                    trente-six milliards \
157                    huit cent cinquante-quatre millions \
158                    sept cent soixante-quinze mille \
159                    huit cent sept");
160    }
161}