1use east_asian_width::east_asian_width;
7
8#[derive(Debug, Clone, Copy)]
10enum Alignment {
11 Left,
12 Right,
13 Center,
14}
15
16fn display_width(text: &str) -> usize {
18 text.chars()
19 .map(|c| east_asian_width(c as u32).as_usize())
20 .sum()
21}
22
23fn align_text(text: &str, width: usize, alignment: Alignment) -> String {
25 let text_width = display_width(text);
26
27 if text_width >= width {
28 return text.to_string();
29 }
30
31 let padding = width - text_width;
32
33 match alignment {
34 Alignment::Left => format!("{}{}", text, " ".repeat(padding)),
35 Alignment::Right => format!("{}{}", " ".repeat(padding), text),
36 Alignment::Center => {
37 let left_padding = padding / 2;
38 let right_padding = padding - left_padding;
39 format!(
40 "{}{}{}",
41 " ".repeat(left_padding),
42 text,
43 " ".repeat(right_padding)
44 )
45 }
46 }
47}
48
49fn format_table(
51 headers: &[&str],
52 rows: &[Vec<&str>],
53 widths: &[usize],
54 alignments: &[Alignment],
55) -> String {
56 let mut result = String::new();
57
58 result.push('┌');
60 for (i, &width) in widths.iter().enumerate() {
61 result.push_str(&"─".repeat(width + 2));
62 if i < widths.len() - 1 {
63 result.push('┬');
64 }
65 }
66 result.push_str("┐\n");
67
68 result.push('│');
70 for (&header, (&width, &alignment)) in headers.iter().zip(widths.iter().zip(alignments.iter()))
71 {
72 result.push(' ');
73 result.push_str(&align_text(header, width, alignment));
74 result.push_str(" │");
75 }
76 result.push('\n');
77
78 result.push('├');
80 for (i, &width) in widths.iter().enumerate() {
81 result.push_str(&"─".repeat(width + 2));
82 if i < widths.len() - 1 {
83 result.push('┼');
84 }
85 }
86 result.push_str("┤\n");
87
88 for row in rows {
90 result.push('│');
91 for (&cell, (&width, &alignment)) in row.iter().zip(widths.iter().zip(alignments.iter())) {
92 result.push(' ');
93 result.push_str(&align_text(cell, width, alignment));
94 result.push_str(" │");
95 }
96 result.push('\n');
97 }
98
99 result.push('└');
101 for (i, &width) in widths.iter().enumerate() {
102 result.push_str(&"─".repeat(width + 2));
103 if i < widths.len() - 1 {
104 result.push('┴');
105 }
106 }
107 result.push_str("┘\n");
108
109 result
110}
111
112fn create_menu(title: &str, options: &[(&str, &str)], width: usize) -> String {
114 let mut result = String::new();
115
116 result.push_str(&format!("┌{}┐\n", "─".repeat(width + 2)));
118 result.push_str(&format!(
119 "│ {} │\n",
120 align_text(title, width, Alignment::Center)
121 ));
122 result.push_str(&format!("├{}┤\n", "─".repeat(width + 2)));
123
124 for (key, description) in options {
126 let option_text = format!("{}: {}", key, description);
127 result.push_str(&format!(
128 "│ {} │\n",
129 align_text(&option_text, width, Alignment::Left)
130 ));
131 }
132
133 result.push_str(&format!("└{}┘\n", "─".repeat(width + 2)));
134 result
135}
136
137fn main() {
138 println!("Text Alignment Examples");
139 println!("======================");
140 println!();
141
142 let texts = vec![
144 "Hello",
145 "こんにちは",
146 "你好世界",
147 "Hello 世界",
148 "Café",
149 "αβγδε",
150 ];
151
152 println!("Basic Alignment (width: 20):");
153 println!("Left aligned:");
154 for text in &texts {
155 println!(" |{}|", align_text(text, 20, Alignment::Left));
156 }
157 println!();
158
159 println!("Right aligned:");
160 for text in &texts {
161 println!(" |{}|", align_text(text, 20, Alignment::Right));
162 }
163 println!();
164
165 println!("Center aligned:");
166 for text in &texts {
167 println!(" |{}|", align_text(text, 20, Alignment::Center));
168 }
169 println!();
170
171 println!("Table Example:");
173 let headers = vec!["ID", "Name", "Language", "Greeting"];
174 let rows = vec![
175 vec!["1", "Alice", "English", "Hello"],
176 vec!["2", "田中太郎", "日本語", "こんにちは"],
177 vec!["3", "李小明", "中文", "你好"],
178 vec!["4", "김철수", "한국어", "안녕하세요"],
179 vec!["5", "José", "Español", "¡Hola!"],
180 ];
181 let widths = vec![3, 12, 10, 15];
182 let alignments = vec![
183 Alignment::Right, Alignment::Left, Alignment::Center, Alignment::Left, ];
188
189 let table = format_table(&headers, &rows, &widths, &alignments);
190 println!("{}", table);
191
192 println!("Menu Example:");
194 let menu_options = vec![
195 ("1", "新建文件 (New File)"),
196 ("2", "打开文件 (Open File)"),
197 ("3", "保存文件 (Save File)"),
198 ("4", "退出程序 (Exit)"),
199 ];
200 let menu = create_menu("文件菜单 (File Menu)", &menu_options, 30);
201 println!("{}", menu);
202
203 println!("Progress Bar Example:");
205 let progress_values = vec![0, 25, 50, 75, 100];
206 for progress in progress_values {
207 let bar_width = 30;
208 let filled = (progress * bar_width) / 100;
209 let empty = bar_width - filled;
210 let bar = format!("{}{}", "█".repeat(filled), "░".repeat(empty));
211 let label = format!("进度 (Progress): {}%", progress);
212 println!(" {} [{}]", align_text(&label, 20, Alignment::Left), bar);
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn test_display_width() {
222 assert_eq!(display_width("Hello"), 5);
223 assert_eq!(display_width("こんにちは"), 10);
224 assert_eq!(display_width("Hello世界"), 9);
225 }
226
227 #[test]
228 fn test_align_left() {
229 assert_eq!(align_text("Hi", 5, Alignment::Left), "Hi ");
230 assert_eq!(
231 align_text("こんにちは", 12, Alignment::Left),
232 "こんにちは "
233 );
234 }
235
236 #[test]
237 fn test_align_right() {
238 assert_eq!(align_text("Hi", 5, Alignment::Right), " Hi");
239 assert_eq!(
240 align_text("こんにちは", 12, Alignment::Right),
241 " こんにちは"
242 );
243 }
244
245 #[test]
246 fn test_align_center() {
247 assert_eq!(align_text("Hi", 6, Alignment::Center), " Hi ");
248 assert_eq!(align_text("Hi", 5, Alignment::Center), " Hi ");
249 assert_eq!(
250 align_text("こんにちは", 12, Alignment::Center),
251 " こんにちは "
252 );
253 }
254}