起因某天我在终端里敲命令,突然想:能不能让输出更炫一点?比如把普通的HELLO变成这种大字
某天我在终端里敲命令,突然想:能不能让输出更炫一点?
比如把普通的 HELLO 变成这种大字:
╔═════════════════════════════════════════════════════╗
║ ║
║ ██╗ ██╗ ███████╗ ██╗ ██╗ ██████╗ ║
║ ██║ ██║ ██╔════╝ ██║ ██║ ██╔═══██╗ ║
║ ███████║ █████╗ ██║ ██║ ██║ ██║ ║
║ ██╔══██║ ██╔══╝ ██║ ██║ ██║ ██║ ║
║ ██║ ██║ ███████╗ ███████╗ ███████╗ ╚██████╔╝ ║
║ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═════╝ ║
║ ║
╚═════════════════════════════════════════════════════╝
说干就干,用 Rust 实现一个!
其实原理特别简单,就三步:
项目很小,就三个文件:
src/
├── main.rs # 命令行入口,处理参数
├── banner.rs # 核心转换逻辑
└── font.rs # 字库定义
首先,我们需要定义每个字符长什么样。用 Unicode 方块字符(█、╗、╔ 等)来画,比传统的 # 或 * 更美观。
每个字符高度固定为 6 行,比如字母 A:
vec![
" █████╗ ", // 第1行
" ██╔══██╗ ", // 第2行
" ██║ ██║ ", // 第3行
" ███████║ ", // 第4行
" ██╔══██║ ", // 第5行
" ╚═╝ ╚═╝ ", // 第6行
]
用一个 HashMap<char, Vec<&str>> 存所有字符,查起来很方便。
关键函数 text_to_ascii,把输入文字转成多行 ASCII 艺术:
pub fn text_to_ascii(text: &str) -> Option<Vec<String>> {
let font_map = get_font_map();
let mut result: Vec<String> = vec![String::new(); FONT_HEIGHT]; // 6个空字符串
for c in text.to_uppercase().chars() {
if let Some(lines) = font_map.get(&c) {
// 把每个字符的每一行追加到结果中
for (i, line) in lines.iter().enumerate() {
result[i].push_str(line);
result[i].push_str(" "); // 字符间距
}
}
}
Some(result)
}
举个例子,输入 "AB":
A,得到 6 行字符串,分别追加到 result[0]~result[5]B,同样追加到每行后面用 Unicode 制表符画边框:
pub fn generate_banner(text: &str, padding: usize) -> String {
let ascii_lines = text_to_ascii(text)?;
// 画上边框
let top = format!("╔{}╗", "═".repeat(width));
// 画内容行(左右加空格 padding)
// ...
// 画下边框
let bottom = format!("╚{}╝", "═".repeat(width));
}
用普通 len() 计算字符串长度会翻车!因为 █ 这种字符占 3 个字节,但显示宽度只有 1。
所以用了 unicode-width 这个 crate:
use unicode_width::UnicodeWidthStr;
let width = "█████╗".width(); // 正确得到显示宽度
没有用 clap 这样的库,直接手写简单处理:
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 || args.contains(&"--help".to_string()) {
print_help();
return;
}
let no_box = args.contains(&"--no-box".to_string());
// ...
}
# 编译
cargo build --release
# 运行
./target/release/ascii-banner "RUST"
# 不要边框
./target/release/ascii-banner "2026" --no-box
输出:
╔══════════════════════════════════════════════╗
║ ║
║ ██████╗ ██╗ ██╗ ███████╗ ████████╗ ║
║ ██╔══██╗ ██║ ██║ ██╔════╝ ╚══██╔══╝ ║
║ ██████╔╝ ██║ ██║ ██████╗ ██║ ║
║ ██╔══██╗ ██║ ██║ ╚════██╗ ██║ ║
║ ██║ ██║ ╚██████╔╝ ███████║ ██║ ║
║ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ║
║ ║
╚══════════════════════════════════════════════╝
这个项目虽然简单,但涵盖了几个有趣的点:
完整代码已开源:github.com/lispking/ascii-banner
如果你也想让终端输出更酷,不妨试试这个小工具!
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!