1const DIGITS: &'static str = "零一二三四五六七八九";
46const TENS_NAME: &'static str = "个十百千";
47const UNIT_RANK: &'static str = "个十百千万亿";
48
49fn digit_pos_to_name(pos: usize) -> char {
50 if pos == 0 {
51 '个'
52 } else if pos % 8 == 0 {
53 '亿'
54 } else if pos % 4 == 0 {
55 '万'
56 } else {
57 TENS_NAME.chars().nth(pos % 4).unwrap()
58 }
59}
60
61struct ResultS (String, bool, char);
62
63fn append_digit(result: ResultS, tuple: (usize, char)) -> ResultS {
64 let (digit, this_unit) = tuple;
65 let ResultS(mut result, pending_zero, last_unit) = result;
66 let this_str = DIGITS.chars().nth(digit).unwrap();
67 if digit == 0 {
68 if UNIT_RANK.find(last_unit).unwrap() > UNIT_RANK.find(this_unit).unwrap() {
69 ResultS(result, true, last_unit)
70 } else {
71 result.push(this_unit);
72 ResultS(result, false, this_unit)
73 }
74 } else {
75 if pending_zero {
76 result.push('零');
77 }
78 result.push(this_str);
79 result.push(this_unit);
80 ResultS(result, false, this_unit)
81 }
82}
83
84pub fn to_chinese_num<N: AsRef<str>>(n: N) -> Option<String> {
85 let n = n.as_ref();
86
87 if n == "0" {
89 return Some("零".to_owned());
90 }
91
92 if !n.chars().all(|x| x.is_digit(10)) || n.len() == 0
94 || n.chars().nth(0).unwrap() == '0' {
95 return None;
96 }
97
98 let v = n.as_bytes().iter().rev().enumerate().map(
99 |(i, c)| ((c - '0' as u8) as usize, digit_pos_to_name(i)))
100 .rev().fold(ResultS(String::new(), false, '个'), append_digit);
101
102 let mut r = v.0;
103 if r.chars().last().unwrap() == '个' {
104 r.pop();;
105 }
106 if r.starts_with("一十") {
107 r.remove(0);
108 }
109 Some(r)
110}
111
112pub trait ToChineseNum {
113 fn to_chinese_num(&self) -> Option<String>;
121}
122
123impl ToChineseNum for usize {
124 fn to_chinese_num(&self) -> Option<String> {
125 to_chinese_num(self.to_string())
126 }
127}
128
129#[test]
130fn empty_number() {
131 let s = to_chinese_num("");
132 assert!(s.is_none());
133}
134
135#[test]
136fn num_0() {
137 let s = to_chinese_num("0").unwrap();
138 assert_eq!(s, "零");
139}
140
141#[test]
142fn num_1() {
143 let s = to_chinese_num("1").unwrap();
144 assert_eq!(s, "一");
145}
146
147#[test]
148fn num_10() {
149 let s = to_chinese_num("10").unwrap();
150 assert_eq!(s, "十");
151}
152
153#[test]
154fn num_12() {
155 let s = to_chinese_num("12").unwrap();
156 assert_eq!(s, "十二");
157}
158
159#[test]
160fn num_20() {
161 let s = to_chinese_num("20").unwrap();
162 assert_eq!(s, "二十");
163}