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}