0x00 介紹 tabulate
tabulate 是一個使用 C++ 17 編寫的庫,它可以制作表格。使用它,把表格對齊、格式化和着色,不在話下!你甚至可以使用 tabulate,將你的表格導出為 Markdown 代碼。下圖是一個使用 tabulate 制作的表格輸出在命令行的樣例:
當然,除了表格,你還可以玩出花樣。看見下面這個馬里奧了嗎?這也是用 tabulate 制作的!源碼在 這里。
0x10 准備
首先你需要安裝 CMake。
創建一個文件夾(下文用 X 代替),作為你使用 tabulate 的地方。再將 include 這個文件夾下載到 X 里。然后在 X 里創建 main.cpp
以及一個 CMakeLists.txt
。
注意:需要下載
include
整個文件夾而不是僅僅下載tabulate
文件夾你可以點擊 這里 下載 tabulate 項目,然后將
include
文件夾復制到 X 中。
將下面的代碼復制進 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.8)
# 這里的 tabulateDemo 可以換為你喜歡的名字
project(tabulateDemo)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
include_directories(include)
add_executable(main main.cpp)
最后 X 文件夾的結構應該是這樣的:
.
├── CMakeLists.txt
├── include
│ └── tabulate
└── main.cpp
請認真核對好 X 的結構!
可前往 ChungZH/tabulatedemo 核對文件結構。
0x20 小試身手
將下面這段代碼復制進 main.cpp
中:
#include "tabulate/table.hpp"
using namespace std;
using namespace tabulate;
int main()
{
Table hellogithub; // 創建一個叫做 hellogithub 的 Table 對象
hellogithub.add_row({"HelloGitHub"});
hellogithub.add_row({"hellogithub.com"});
hellogithub[1][0].format()
.font_style({FontStyle::underline});
hellogithub.add_row({"github.com/521xueweihan/HelloGitHub"});
hellogithub[2][0].format()
.font_style({FontStyle::underline});
hellogithub.add_row({"xueweihan NB!!!"});
cout << hellogithub << endl;
return 0;
}
-
如果你使用的是 Linux/MacOS 系統,請在終端進入 X 文件夾並輸入以下命令:
mkdir build cd build cmake .. make ./main
-
如果你使用的是 Windows 系統和 MinGW,請檢查是否安裝
mingw32-make.exe
,並在終端中進入 X 文件夾,輸入:mkdir build cd build cmake .. mingw32-make ./main.exe
-
如果你使用 Windows 以及 MSVC,在終端中輸入:
mkdir build cd build cmake ..
然后使用 Visual Studio 打開 build
文件夾下的 tabulateDemo.sln
來運行。
如果沒有問題,那么你應該會在終端里看到:
0x30 格式化表格
請先認真分析 0x20 小試身手 章節中的代碼並嘗試着修改一下它!
0x31 Word Wrapping
為了防止表格中的內容過長導致不整齊,你可以指定表格每一列的寬度,tabulate 就會自動幫你換行。語法如下:
// 將表格第 0 行第 0 列的寬度設為20
table[0][0].format().width(20);
除了自動換行,你也可以在內容中使用 \n
來手動設置換行。
這是一個 Word Wrapping 的例子:
#include "tabulate/table.hpp"
using namespace std;
using namespace tabulate;
int main()
{
Table table;
table.add_row({"This paragraph contains a veryveryveryveryveryverylong word. The long word will break and word wrap to the next line.",
"This paragraph \nhas embedded '\\n' \ncharacters and\n will break\n exactly where\n you want it\n to\n break."});
table[0][0].format().width(20); // 設置第 0 行第 0 列的寬度為 20
table[0][1].format().width(50); // 設置第 0 行第 1 列的寬度為 50
cout << table << endl;
return 0;
}
return 0;
}
-
第 0 行第 0 列的文字是不是很長?但是設置了它的寬度后,就不用擔心了。tabulate 將會幫你自動換行。如果不設置的話,表格就會變得很不整齊,你也可以嘗試一下。
-
第 0 行第 1 列的內容里運用了
\n
的換行符,所以即使我們給它設置了 50 的寬度,也會先根據內容里的\n
換行符來換行。 -
值得注意的是,tabulate 會自動刪除每一行內容兩邊的空白字符。
0x32 字體對齊
tabulate 支持三種對齊設置:左、中和右。默認情況下,全部內容都會靠左對齊。
要手動設置對齊方式,可以使用 .format().font_align(方向)
。
舉一個例子:
#include "tabulate/table.hpp"
using namespace std;
using namespace tabulate;
int main()
{
Table hellogithub;
hellogithub.add_row({"HelloGitHub"});
hellogithub[0][0].format()
.font_align(FontAlign::center); // 設置居中對齊
hellogithub.add_row({"hellogithub.com"});
hellogithub[1][0].format()
.font_align(FontAlign::left); // 設置靠左對齊
hellogithub.add_row({"github.com/521xueweihan/HelloGitHub"});
hellogithub[2][0].format()
.font_align(FontAlign::center); // 設置居中對齊
hellogithub.add_row({"xueweihan NB!!!"});
hellogithub[3][0].format()
.font_align(FontAlign::right); // 設置靠右對齊
hellogithub[0][0].format().width(50);
cout << hellogithub << endl;
return 0;
}
0x33 字體樣式
tabulate 支持以下八種字體樣式:
-
粗體
bold
-
深色
dark
-
斜體
italic
-
下划線
underline
-
閃爍
blink
-
翻轉
reverse
-
隱藏
concealed
-
刪除線
crossed
某些樣式可能會因為終端的原因而無法顯示。
如:粗體、深色、斜體、閃爍等樣式,請慎用。
要使用這些樣式,可以調用 .format().font_style({...})
。樣式也可以疊加使用。
0x34 顏色
你可以對表格的字體、邊框、角以及列分隔符號設置它們的前景或背景顏色。
tabulate 支持 8 種顏色:
-
灰色
gray
-
紅色
red
-
綠色
green
-
黃色
yellow
-
藍色
blue
-
洋紅色
magenta
-
青色
cyan
-
白色
white
可以通過 .format().<element>_color(顏色)
的方式定義前景色或通過 .format().<element>_background_color(顏色)
的方式定義背景色。
#include "tabulate/table.hpp"
using namespace tabulate;
using namespace std;
int main()
{
Table colors;
colors.add_row({"Font Color is Red", "Font Color is Blue", "Font Color is Green"});
colors.add_row({"Everything is Red", "Everything is Blue", "Everything is Green"});
colors.add_row({"Font Background is Red", "Font Background is Blue", "Font Background is Green"});
colors[0][0].format()
.font_color(Color::red)
.font_style({FontStyle::bold});
colors[0][1].format()
.font_color(Color::blue)
.font_style({FontStyle::bold});
colors[0][2].format()
.font_color(Color::green)
.font_style({FontStyle::bold});
colors[1][0].format()
.border_left_color(Color::red)
.border_left_background_color(Color::red)
.font_background_color(Color::red)
.font_color(Color::red);
colors[1][1].format()
.border_left_color(Color::blue)
.border_left_background_color(Color::blue)
.font_background_color(Color::blue)
.font_color(Color::blue);
colors[1][2].format()
.border_left_color(Color::green)
.border_left_background_color(Color::green)
.font_background_color(Color::green)
.font_color(Color::green)
.border_right_color(Color::green)
.border_right_background_color(Color::green);
colors[2][0].format()
.font_background_color(Color::red)
.font_style({FontStyle::bold});
colors[2][1].format()
.font_background_color(Color::blue)
.font_style({FontStyle::bold});
colors[2][2].format()
.font_background_color(Color::green)
.font_style({FontStyle::bold});
cout << colors << endl;
return 0;
}
0x35 邊框、角
你可以對表格的邊框和角的文本、顏色或背景顏色進行自定義。
你可以使用 .corner(..)
、.corner_color(..)
和 corner_background_color(..)
來對所有的角設置一個共同的樣式。你也可以使用 .border(..)
、.border_color(..)
和 .border_background_color(..)
來對所有的邊框設置一個共同的樣式。
這是一個單獨設定所有邊框和角的示例:
#include <tabulate/table.hpp>
using namespace tabulate;
int main()
{
Table table;
table.add_row({"ᛏᚺᛁᛊ ᛁᛊ ᚨ ᛊᛏᛟᚱy ᛟᚠᚨ ᛒᛖᚨᚱ ᚨᚾᛞ\n"
"ᚨ ᚹᛟᛚᚠ, ᚹᚺᛟ ᚹᚨᚾᛞᛖᚱᛖᛞ ᛏᚺᛖ\n"
"ᚱᛖᚨᛚᛗᛊ ᚾᛁᚾᛖ ᛏᛟ ᚠᚢᛚᚠᛁᛚᛚ ᚨ ᛈᚱᛟᛗᛁᛊᛖ\n"
"ᛏᛟ ᛟᚾᛖ ᛒᛖᚠᛟᚱᛖ; ᛏᚺᛖy ᚹᚨᛚᚲ ᛏᚺᛖ\n"
"ᛏᚹᛁᛚᛁᚷᚺᛏ ᛈᚨᛏᚺ, ᛞᛖᛊᛏᛁᚾᛖᛞ ᛏᛟ\n"
"ᛞᛁᛊcᛟᚹᛖᚱ ᛏᚺᛖ ᛏᚱᚢᛏᚺ\nᛏᚺᚨᛏ ᛁᛊ ᛏᛟ cᛟᛗᛖ."});
table.format()
.multi_byte_characters(true)
// Font styling
.font_style({FontStyle::bold, FontStyle::dark})
.font_align(FontAlign::center)
.font_color(Color::red)
.font_background_color(Color::yellow)
// Corners
.corner_top_left("ᛰ")
.corner_top_right("ᛯ")
.corner_bottom_left("ᛮ")
.corner_bottom_right("ᛸ")
.corner_top_left_color(Color::cyan)
.corner_top_right_color(Color::yellow)
.corner_bottom_left_color(Color::green)
.corner_bottom_right_color(Color::red)
// Borders
.border_top("ᛜ")
.border_bottom("ᛜ")
.border_left("ᚿ")
.border_right("ᛆ")
.border_left_color(Color::yellow)
.border_right_color(Color::green)
.border_top_color(Color::cyan)
.border_bottom_color(Color::red);
std::cout << table << std::endl;
return 0;
}
0x36 基於范圍的迭代
一個一個設置表格的樣式是不是很麻煩?tabulate 提供了迭代器,支持對表、行和列的迭代,更方便地格式化表格。
#include <tabulate/table.hpp>
using namespace tabulate;
int main() {
Table table;
table.add_row({"Company", "Contact", "Country"});
table.add_row({"Alfreds Futterkiste", "Maria Anders", "Germany"});
table.add_row({"Centro comercial Moctezuma", "Francisco Chang", "Mexico"});
table.add_row({"Ernst Handel", "Roland Mendel", "Austria"});
table.add_row({"Island Trading", "Helen Bennett", "UK"});
table.add_row({"Laughing Bacchus Winecellars", "Yoshi Tannamuri", "Canada"});
table.add_row({"Magazzini Alimentari Riuniti", "Giovanni Rovelli", "Italy"});
// 設置每一行的寬度
table.column(0).format().width(40);
table.column(1).format().width(30);
table.column(2).format().width(30);
// 遍歷第一行中的單元格
for (auto& cell : table[0]) {
cell.format()
.font_style({FontStyle::underline})
.font_align(FontAlign::center);
}
// 遍歷第一列中的單元格
for (auto& cell : table.column(0)) {
if (cell.get_text() != "Company") {
cell.format()
.font_align(FontAlign::right);
}
}
// 遍歷表格中的行
size_t index = 0;
for (auto& row : table) {
row.format()
.font_style({FontStyle::bold});
// 輪流把整行的背景設為藍色
if (index > 0 && index % 2 == 0) {
for (auto& cell : row) {
cell.format()
.font_background_color(Color::blue);
}
}
index += 1;
}
std::cout << table << std::endl;
}
0x37 嵌套表格
在 tabulate 中嵌套表格很容易,因為 Table.add_row(...)
這個函數可以接受 std::string
類型和 tabulate::Table
。下面是一個嵌套表格的例子:
#include "tabulate/table.hpp"
using namespace tabulate;
using namespace std;
int main() {
Table hellogithub;
hellogithub.add_row({"HelloGitHub"});
hellogithub[0][0]
.format()
.font_background_color(Color::blue)
.font_align(FontAlign::center);
Table hglink;
hglink.add_row({"GitHub repo", "Website"});
hglink.add_row({"github.com/521xueweihan/HelloGitHub", "hellogithub.com"});
hellogithub.add_row({hglink}); // 嵌套!
cout << hellogithub << endl;
return 0;
}
0x40 導出
0x41 Markdown
可以使用 MarkdownExporter
來將一個表格導出為 GFM 風格的 Markdown。
#include "tabulate/markdown_exporter.hpp" // 注意這個頭文件
#include "tabulate/table.hpp"
using namespace tabulate;
using namespace std;
int main() {
Table hellogithub;
hellogithub.add_row({"HelloGitHub"});
hellogithub[0][0].format().font_style({FontStyle::bold}); // 加粗樣式,在 Markdown 中可以表現出來
hellogithub.add_row({"GitHub repo: github.com/521xueweihan/HelloGitHub"});
hellogithub.add_row({"Website: hellogithub.com"});
// 導出為 Markdown
MarkdownExporter exporter;
auto markdown = exporter.dump(hellogithub);
cout << hellogithub << endl << endl;
cout << "Markdown Source:\n\n" << markdown << endl;
return 0;
}
導出效果如下:
HelloGitHub |
---|
GitHub repo: github.com/521xueweihan/HelloGitHub |
Website: hellogithub.com |
注意:Markdown 不能指定每一個單元格的對齊樣式,只能指定一列的對齊樣式,像這樣
hg.column(1).format().font_align(FontAlign::center);
。
0x50 尾聲
如果想要更詳細地了解 tabulate 的用法,請查看官方文檔 https://github.com/p-ranav/tabulate 。
本文是作者的第一次關於此類型文章的嘗試,如有不足之處,請指正,謝謝!
再見!
關注公眾號加入交流群