hutools/convert/
number_chinese.rs

1use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
2
3#[cfg(test)]
4mod tests {
5    use super::*;
6
7    #[test]
8    fn to_chinese_number_test() {
9        let number = 4123;
10        let result = ChineseNumber::from(number);
11        assert_eq!(result.to_string(), "四千一百二十三");
12        let result = result.to_complex();
13        assert_eq!(result.to_string(), "肆仟壹佰贰拾叁")
14    }
15
16    #[test]
17    fn to_chinese_num() {
18        let number = 1234567;
19        let result = ChineseNumber::from(number);
20        assert_eq!(result.to_string(), "一百二十三万四千五百六十七");
21        let n = ChineseNumber::from(result.to_string());
22        assert_eq!(n.value, number);
23    }
24    #[test]
25    fn to_chinese_number_with_many_zero() {
26        let number = 100001;
27        let result = ChineseNumber::from(number).to_string();
28        assert_eq!(result, "一十万零一");
29        let result = ChineseNumber::from(result);
30        assert_eq!(result.value, number);
31    }
32
33    #[test]
34    fn chinese_to_number_test() {
35        let number = 1324;
36        let chinese = ChineseNumber::from(number).to_string();
37        let result = ChineseNumber::from(chinese);
38        assert_eq!(result.value, number);
39    }
40
41    #[test]
42    fn chinese_to_number_two_thousand() {
43        let number = 2000;
44        let chinese = ChineseNumber::from(number).to_string();
45        let result = ChineseNumber::from(chinese);
46        assert_eq!(result.value, number);
47    }
48    #[test]
49    fn chinese_calc_test() {
50        let chinese = ChineseNumber::from(1234);
51        let other_chinese = ChineseNumber::from(4321);
52        let result = chinese + other_chinese;
53        assert_eq!(result.value, 5555);
54    }
55    #[test]
56    fn chinese_calc_with_u32_test() {
57        let chinese = ChineseNumber::from(1234);
58        let result = chinese + 4321;
59        assert_eq!(result.value, 5555)
60    }
61}
62#[derive(Copy, Clone, Debug, Eq, PartialEq)]
63enum ChineseNumberUnit {
64    Simple,
65    Complex,
66    SimpleMoney,
67    ComplexMoney,
68}
69
70#[derive(Clone, Debug)]
71pub struct ChineseNumber {
72    value: u32,
73    unit: ChineseNumberUnit,
74}
75
76impl ToString for ChineseNumber {
77    fn to_string(&self) -> String {
78        match self.unit {
79            ChineseNumberUnit::Simple => to(self.value, self.unit),
80            ChineseNumberUnit::Complex => to(self.value, self.unit),
81            ChineseNumberUnit::SimpleMoney => {
82                let v = to(self.value, ChineseNumberUnit::Simple);
83                format!("{v}元整")
84            }
85            ChineseNumberUnit::ComplexMoney => {
86                let v = to(self.value, ChineseNumberUnit::Complex);
87                format!("{v}元整")
88            }
89        }
90    }
91}
92
93impl From<String> for ChineseNumber {
94    fn from(str: String) -> Self {
95        let string = format!("{str} ");
96        let mut result = 0;
97        let mut tmp = 0;
98        for x in string.chars() {
99            let char = &x.to_string();
100            if is_number_char(char) {
101                let n = index_number(char);
102                if n.is_some() {
103                    let v = index_number(char);
104                    tmp = v.unwrap() as u32;
105                }
106            } else {
107                let chinese_unit = get_chinese_unit(char);
108                if let Some(..) = chinese_unit {
109                    let cu = chinese_unit.unwrap();
110                    let ChineseUnit(_, v, is_unit) = cu;
111                    if is_unit {
112                        let t = result + tmp;
113                        result = t * v;
114                    } else {
115                        let t = tmp * v;
116                        tmp = 0;
117                        result += t;
118                    }
119                }
120            }
121        }
122        ChineseNumber {
123            value: result,
124            unit: ChineseNumberUnit::Simple,
125        }
126    }
127}
128
129impl ChineseNumber {
130    pub fn to_simple(&self) -> ChineseNumber {
131        ChineseNumber {
132            value: self.value,
133            unit: ChineseNumberUnit::Simple,
134        }
135    }
136    pub fn to_complex(&self) -> ChineseNumber {
137        ChineseNumber {
138            value: self.value,
139            unit: ChineseNumberUnit::Complex,
140        }
141    }
142    pub fn to_simple_money(&self) -> ChineseNumber {
143        ChineseNumber {
144            value: self.value,
145            unit: ChineseNumberUnit::SimpleMoney,
146        }
147    }
148    pub fn to_complex_money(&self) -> ChineseNumber {
149        ChineseNumber {
150            value: self.value,
151            unit: ChineseNumberUnit::ComplexMoney,
152        }
153    }
154}
155
156impl Add for ChineseNumber {
157    type Output = ChineseNumber;
158
159    fn add(self, rhs: Self) -> Self::Output {
160        let value = self.value + rhs.value;
161        ChineseNumber {
162            value,
163            unit: self.unit,
164        }
165    }
166}
167impl Add<u32> for ChineseNumber {
168    type Output = ChineseNumber;
169    fn add(self, rhs: u32) -> Self::Output {
170        ChineseNumber {
171            unit: self.unit,
172            value: self.value + rhs,
173        }
174    }
175}
176
177impl AddAssign for ChineseNumber {
178    fn add_assign(&mut self, rhs: Self) {
179        self.value += rhs.value;
180    }
181}
182
183impl AddAssign<u32> for ChineseNumber {
184    fn add_assign(&mut self, rhs: u32) {
185        self.value -= rhs;
186    }
187}
188
189impl Sub for ChineseNumber {
190    type Output = ChineseNumber;
191
192    fn sub(self, rhs: Self) -> Self::Output {
193        let value = self.value - rhs.value;
194        ChineseNumber {
195            value,
196            unit: self.unit,
197        }
198    }
199}
200
201impl SubAssign for ChineseNumber {
202    fn sub_assign(&mut self, rhs: Self) {
203        self.value = self.value - rhs.value;
204    }
205}
206
207impl Mul for ChineseNumber {
208    type Output = ChineseNumber;
209
210    fn mul(self, rhs: Self) -> Self::Output {
211        let value = self.value * rhs.value;
212        ChineseNumber {
213            value,
214            unit: self.unit,
215        }
216    }
217}
218
219impl MulAssign for ChineseNumber {
220    fn mul_assign(&mut self, rhs: Self) {
221        self.value = self.value * rhs.value
222    }
223}
224impl Div for ChineseNumber {
225    type Output = ChineseNumber;
226
227    fn div(self, rhs: Self) -> Self::Output {
228        let value = self.value / rhs.value;
229        ChineseNumber {
230            value,
231            unit: self.unit,
232        }
233    }
234}
235
236impl DivAssign for ChineseNumber {
237    fn div_assign(&mut self, rhs: Self) {
238        self.value = self.value / rhs.value
239    }
240}
241
242impl From<u32> for ChineseNumber {
243    fn from(i: u32) -> Self {
244        ChineseNumber {
245            value: i,
246            unit: ChineseNumberUnit::Simple,
247        }
248    }
249}
250
251#[derive(Clone, Eq, PartialOrd, PartialEq, Ord)]
252struct ChineseUnit(&'static str, u32, bool);
253
254const CHINESE_UNITS: [ChineseUnit; 6] = [
255    ChineseUnit(" ", 1, false),
256    ChineseUnit("十", 10, false),
257    ChineseUnit("百", 100, false),
258    ChineseUnit("千", 1000, false),
259    ChineseUnit("万", 10000, true),
260    ChineseUnit("亿", 100000000, true),
261];
262
263fn get_chinese_unit(str: &str) -> Option<ChineseUnit> {
264    CHINESE_UNITS.iter().find(|&x| x.0 == str).cloned()
265}
266
267const NUMBERS: [&str; 10] = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
268fn is_number_char(str: &str) -> bool {
269    NUMBERS.contains(&str)
270}
271
272fn index_number(str: &str) -> Option<usize> {
273    NUMBERS.iter().position(|&v| v == str)
274}
275
276fn to(mut number: u32, unit: ChineseNumberUnit) -> String {
277    let section_unit_char = ["", "万", "亿", "万亿"];
278    let mut unit_pos = 0;
279    let mut need_zero = false;
280    let mut result = String::new();
281    while number > 0 {
282        let section = number % 10000;
283        let s = section_to(section, unit);
284        result = if need_zero {
285            format!("{s}{}{}{result}", section_unit_char[unit_pos], "零")
286        } else {
287            format!("{s}{}{result}", section_unit_char[unit_pos])
288        };
289        need_zero = is_need_zone(section);
290        unit_pos += 1;
291        number /= 10000;
292    }
293    return result;
294
295    fn is_need_zone(number: u32) -> bool {
296        number > 0 && number < 1000
297    }
298}
299
300fn section_to(mut number: u32, unit: ChineseNumberUnit) -> String {
301    let list = get_list_by_unit(unit);
302    let unit_char = get_unit_char_by_unit(unit);
303    let mut unit_pos = 0;
304    let mut result = String::new();
305    let mut need_zone = true;
306    while number > 0 {
307        let pos = (number % 10) as usize;
308        if pos == 0 {
309            if number == 0 || !need_zone {
310                need_zone = true;
311                result = format!("{}{result}", list[0]);
312            }
313        } else {
314            need_zone = false;
315            result = format!("{}{}{result}", list[pos], unit_char[unit_pos]);
316        }
317        unit_pos += 1;
318        number /= 10;
319    }
320    result
321}
322
323fn get_unit_char_by_unit(unit: ChineseNumberUnit) -> [&'static str; 4] {
324    if unit == ChineseNumberUnit::Simple || unit == ChineseNumberUnit::SimpleMoney {
325        ["", "十", "百", "千"]
326    } else {
327        ["", "拾", "佰", "仟"]
328    }
329}
330
331fn get_list_by_unit(unit: ChineseNumberUnit) -> [&'static str; 10] {
332    if unit == ChineseNumberUnit::Simple || unit == ChineseNumberUnit::SimpleMoney {
333        ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
334    } else {
335        ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"]
336    }
337}