Rust中带终端ANSI转义码的字符串print!格式化对齐问题
解决方法
核心逻辑是绕开标准库格式化对字符串总长度的计算,改为手动基于纯文本内容的显示长度计算填充空格:
- 先提取不带任何样式的纯文件名,计算它的实际显示长度
- 给纯文件名套上对应的ANSI样式
- 根据你需要的列宽,减去纯文本的显示长度,得到需要补充的空格数,手动拼接空格后输出即可
修改后的核心代码示例
use std::{env , fs, path::PathBuf}; use ansi_term::Colour; use term_size; fn main() { const COL_WIDTH: usize = 25; println!("{esc}[2J{esc}[1;1H", esc = 27 as char); // 清屏 let term_cols = match term_size::dimensions() { Some((cols,_)) => cols, None => 0}; let mut files: Vec<PathBuf> = fs::read_dir(env::current_dir().unwrap()) .unwrap() .filter_map(|file| Some(file.unwrap().path())) .collect(); files.sort(); let max_columns = term_cols / 30 ; let max_rows = (files.len() / max_columns) + 1; for i in 0..max_rows { for j in 0..max_columns { let index = i+(max_rows*j); if index >= files.len() { break; } // 先提取纯文件名 let file_name = files[index].file_name().unwrap().to_str().unwrap(); // 计算纯文本的实际显示字符数,英文场景下直接使用即可,多字节全角字符可配合字符宽度计算工具调整 let real_display_len = file_name.chars().count(); // 渲染样式 let styled_name = if files[index].is_dir() { Colour::Black.on(Colour::White).paint(file_name).to_string() } else if files[index].symlink_metadata().unwrap().file_type().is_symlink() { Colour::Cyan.bold().italic().underline().paint(file_name).to_string() } else { Colour::Fixed(15).bold().paint(file_name).to_string() }; // 手动补空格 let padding = " ".repeat(COL_WIDTH.saturating_sub(real_display_len)); print!("|{}{}", styled_name, padding); } print!("\n"); } }
边缘场景适配
如果使用场景需要兼容中文、emoji等全角字符,普通的字符计数会出现宽度偏差,可以引入用于计算字符显示宽度的工具库,累加每个字符的实际显示宽度得到总宽度后,再计算需要填充的空格即可。
内容的提问来源于stack exchange,提问作者Rakshit Shetty
相关产品推荐
相关产品推荐

