我正在尝试打印一个比纯文本表示更赏心悦目的表格。基本上我想转换这样的东西:
+-----+--------+
| age | weight |
+-----+--------+
| 10 | 100 |
| 80 | 500 |
+-----+--------+
像这样:
┌─────┬────────┐
| age | weight |
├─────┼────────┤
│ 10 │ 100 │
│ 80 │ 500 │
└─────┴────────┘
这是我在终端中看到的屏幕截图:
注意行之间的间隙。我的问题是它们没有正确连接,而其他使用 ANSI 打印的 Unix 工具在终端中看起来很好。例如,树,如果我在终端中运行
tree -A
`我得到这个:
注意垂直线是如何连接在一起的。这很有趣,因为当我将树的输出复制并粘贴到文本编辑器并运行我的脚本时,我得到如下内容:
显然我错过了一些关于在终端中打印 ANSI 字符的信息,并且无法通过谷歌搜索找到任何有关它的信息。谁能解释一下这个话题?
我想我应该回答我自己的问题。经过一番研究以及朋友和老板 Linus 的帮助后,我发现我需要强制终端首先进入图形模式,然后打印特殊字符,然后返回到文本模式。切换到图形模式的ascii代码是14,15将返回文本模式。这是 ruby 中的代码:
printf("%c\n", 14)
printf("%c ", 0x6A) # ┘
printf("%c ", 0x6B) # ┐
printf("%c ", 0x6C) # ┌
printf("%c ", 0x6D) # └
printf("%c ", 0x6E) # ┼
printf("%c ", 0x71) # ─
printf("%c ", 0x74) # ├
printf("%c ", 0x75) # ┤
printf("%c ", 0x76) # ┴
printf("%c ", 0x77) # ┬
printf("%c\n", 0x78) # │
a = sprintf("%c", 0x6C) + # ┌
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c\n", 0x6B) + # ┐
sprintf("%c", 0x78) + # │
#print(" ")
" " +
sprintf("%c\n", 0x78) + # │
sprintf("%c", 0x6D) + # └
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x71) + # ─
sprintf("%c", 0x6A) # ┘
puts a
printf("%c\n", 15)
您确实应该研究 ncurses 及其变体。尽管它最初是为 C 语言编写的,但有一系列不同的语言绑定。它提供了一套相当丰富的库,用于生成带有窗口、菜单、盒装边框等的 TUI(文本 UI)。 首先访问维基百科来查找其他一些参考资料。
首先感谢 Allen Bargi 提出这个问题并提供他的 ruby 解决方案。这帮助我为 bash 编写了一个解决方案,因此不依赖 ruby。
首先我们可以打印出画线字符列表来演示它是如何工作的:
printf "\e(0" ; # Begin Graphics
printf "\x6A " ; # ┘
printf "\x6B " ; # ┐
printf "\x6C " ; # ┌
printf "\x6D " ; # └
printf "\x6E " ; # ┼
printf "\x71 " ; # ─
printf "\x74 " ; # ├
printf "\x75 " ; # ┤
printf "\x76 " ; # ┴
printf "\x77 " ; # ┬
printf "\x78 " ; # │
printf "\e(B" ; # End Graphics
printf "\n";
输出如下所示:
┘ ┐ ┌ └ ┼ ─ ├ ┤ ┴ ┬ │
现在我可以打印问题中格式的示例表
# Header Top
printf "\e(0" ; # Begin Graphics
printf "\x6C" ; # ┌
printf "%.0s\x71" {1..5} ; # ─ x5
printf "\x77" ; # ┬
printf "%.0s\x71" {1..8} ; # ─ x8
printf "\x6B" ; # ┐
printf "\n";
# Column Names
printf "\x78" ; # │
printf "\e(B" ; # End Graphics
printf " age "
printf "\e(0" ; # Begin Graphics
printf "\x78" ; # │
printf "\e(B" ; # End Graphics
printf " weight "
printf "\e(0" ; # Begin Graphics
printf "\x78" ; # │
printf "\n";
# Header Bottom
printf "\x74" ; # ├
printf "%.0s\x71" {1..5} ; # ─ x5
printf "\x6E" ; # ┼
printf "%.0s\x71" {1..8} ; # ─ x8
printf "\x75" ; # ┤
printf "\n";
# Data Row. Be careful to print the data normally
printf "\x78" ; # │
printf "\e(B" ; # End Graphics
printf " %3s " 10
printf "\e(0" ; # Begin Graphics
printf "\x78" ; # │
printf "\e(B" ; # End Graphics
printf " %6s " 100
printf "\e(0" ; # Begin Graphics
printf "\x78" ; # │
printf "\n";
# Data Row. Be careful to print the data normally
printf "\x78" ; # │
printf "\e(B" ; # End Graphics
printf " %3s " 80
printf "\e(0" ; # Begin Graphics
printf "\x78" ; # │
printf "\e(B" ; # End Graphics
printf " %6s " 500
printf "\e(0" ; # Begin Graphics
printf "\x78" ; # │
printf "\n";
# Finally the Table Bottom
printf "\x6D" ; # └
printf "%.0s\x71" {1..5} ; # ─ x5
printf "\x76" ; # ┴
printf "%.0s\x71" {1..8} ; # ─ x8
printf "\x6A" ; # ┘
printf "\n";
printf "\e(B" ; # End Graphics
这是结果(Stack Overflow 显示它,行之间有间隙,但在我的各种终端上我没有看到任何间隙):
┌─────┬────────┐
│ age │ weight │
├─────┼────────┤
│ 10 │ 100 │
│ 80 │ 500 │
└─────┴────────┘
如果你想使用Python,那么
\e
可以替换为\x1B
:
print("\x1B(0", end='') # Begin Graphics
print("\x1B(B", end='') # End Graphics
print("\x6A", end='') # ┘
# etc...
我还尝试看看是否有一种很好的方法将其与 util-linux 命令集成
column
,但不幸的是,这不会填充表格的最后一列,除非您将其右对齐。一个模式是始终在每一行前面加上一个虚拟的单空格列:
$ sep=`printf "\e(0\x78\e(B"`
$ printf "Age,Weight\n10,100\n80,500\n" | sed -e 's/^/ ,/' -e 's/$/, /' | column -t -s ',' -o " $sep "
│ Age │ Weight │
│ 10 │ 100 │
│ 80 │ 500 │