基于C++的Latex表格代码自动生成

目录

一. 前言

二.代码实现

三.生成结果


一. 前言

相信做科研的同学一定经常接触到Latex。Latex做为脚本控制的自动排版系统,其生成的文本整洁,清楚,对于图表的自动布局,能够有效的安排页面空间,使用户的文本可以直接获得印刷出版物级别的质量。但是Latex有一个非常蛋疼的地方,就是表格。Latex表格是通过格式化的表示形式实现其排版的,其过程繁琐,容易出错。每次想到要将一个大的表格排到Latex里,就头疼。鉴于表格生成的复杂性,一些表格代码自动生成工具应运而生。我个人最经常用的是Table Generator。在线访问Table Generator,将excel数据粘贴到该网站,通过一个非常简洁的交互页面,就能够直接生成latex表格代码,操作界面如下图:

但是使用该工具仍然有问题。比如一些调整表格风格的代码还需要后续添加,一些数据按照大小极值需要加粗,在Table Generator中需要人工的标定,依然费时费力。鉴于以后要经常使用,所以决定基于C++写一个表格代码生成程序,以方便后续使用。


二.代码实现

首先我们要先将需要表格化的数据,存储在txt。我们需要给出对应的信息。这里我们举两个例子:

caption for table
1 15 0
3
Method1 Method2 Method3 Method4 Method5 Method6 Method7 Method8 Method9 Method10 Method11 Method12 Method13 Method14 Method15
M1 M2 M3
Max
1.2 1.1 1.4 5.6 5.3 5.6 2.2 3.1 0.4 15.6 25.3 45.6 11.2 51.1 21.4
0.2 0.1 0.4 15.6 15.3 15.6 72.2 33.1 0.4 65.6 125.3 145.6 1.2 351.1 221.4
21.1 31.1 51.4 75.6 95.3 25.6 22.2 23.1 20.4 215.6 225.3 245.6 211.2 251.1 221.4

/*
第一行:行label的基本格式,p1:数据列数,p2:第一行label数,p3:第二行label数;
第二行:列label的基本格式,p1:数据行数;
第三行:行label第一行label的string list;
第四行:行label第二行label的string list;
第五行:列label的string list
第六行:Max,加粗每个对应数据组最大值;Min,加粗每个对应数据组最小值
第七行及其他: 数据本身,默认float类型
*/

这是一个表格数据在txt存储的形式,包括行的标识以及列的标识,都有清楚的对应关系。通过指定Max或者Min,程序能够自动加粗每一行的最大或者最小数据,而不再需要人工查找。这里默认的数据类型是float。

caption for table
2 5 3
3
Method1 Method2 Method3 Method4 Method5
Q1 Q2 Q3
M1 M2 M3
Max
1.2 1.1 1.4 5.6 5.3 5.6 2.2 3.1 0.4 15.6 25.3 45.6 11.2 51.1 21.4
0.2 0.1 0.4 15.6 15.3 15.6 72.2 33.1 0.4 65.6 125.3 145.6 1.2 351.1 221.4
21.1 31.1 51.4 75.6 95.3 25.6 22.2 23.1 20.4 215.6 225.3 245.6 211.2 251.1 221.4

/*
第一行:行label的基本格式,p1:数据列数,p2:第一行label数,p3:第二行label数;
第二行:列label的基本格式,p1:数据行数;
第三行:行label第一行label的string list;
第四行:行label第二行label的string list;
第五行:列label的string list
第六行:Max,加粗每个对应数据组最大值;Min,加粗每个对应数据组最小值
第七行及其他: 数据本身,默认float类型
*/

与第一个例子类似,这个表格稍微复杂,行标识有两级。在实际使用中,因为对每一个方法可能有不同的度量(Q1\Q2\Q3),要放在一个表格中,那么支持两级行标识就变的比较实用。

有了数据的存储方法,剩下的就是写一个程序,读取这些数据,并生成Latex表格代码了。数据载入以及生成的C++代码如下:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

class LatexTable {

private:

	vector<string> firstRowLabel;
	vector<string> subRowLabel;
	vector<string> columnLabel;
	string orderName;//Max, Min, Non;
	vector<vector<float>> data;
	string caption;
	string fileName;

public:

	void LatexTable_init(string fileName_input) {

		fileName = fileName_input;
		LatexTable_Load();
		Latextable_Write();
	}

private:

	void LatexTable_Load() {

		int r1, r2, r3;
		int r_final;
		int c1;
		
		fstream out2;
		out2.open(fileName, ios::in);

		getline(out2, caption);

		out2 >> r1>>r2>>r3>>c1;

		for (int i = 0; i < r2; i++) {

			string firstRowLabel_i;
			out2 >> firstRowLabel_i;
			firstRowLabel.push_back(firstRowLabel_i);

		}

		r_final = r2;

		if (r1 == 2) {			

			for (int i = 0; i < r3; i++) {

				string subRowLabel_i;
				out2 >> subRowLabel_i;
				subRowLabel.push_back(subRowLabel_i);

			}

			r_final = r_final* r3;

		}

		for (int i = 0; i < c1; i++) {

			string columnLabel_i;
			out2 >> columnLabel_i;
			columnLabel.push_back(columnLabel_i);

		}

		//load order

		out2 >> orderName;

		//load data
		for (int i = 0; i < c1; i++) {

			vector<float> data_i;
			for (int j = 0; j < r_final; j++) {

				float r_final_i;
				out2 >> r_final_i;
				data_i.push_back(r_final_i);
			
			}
			data.push_back(data_i);		
		
		}	

		cout << "Data loaded finished." << endl;
	
	}

	void Latextable_Write() {

		string fileName_Save;
		int findTxt = fileName.find_last_of(".txt");
		fileName_Save = fileName.substr(0, findTxt-3) + "_Latex.txt";
		ofstream f1(fileName_Save, ios::app);
		int r_final;
		if (subRowLabel.size() == 0) {
			r_final = firstRowLabel.size();
		}
		else {
			r_final = firstRowLabel.size() * subRowLabel.size();
		}

		//1.首先写入label的序列
		f1 << "\\begin{table*}[]" << endl;
		f1 << "\\centering" << endl;
		f1 << "\\caption{" << caption << ".}" << endl;
		f1 << "\\begin{tabular}{";
		f1 << "c|";
		for (int i = 0; i < r_final; i++) {
			f1 << "c";
		}
		f1 << "}";
		f1 << "\\toprule[1pt]" << endl;

		if (subRowLabel.size() == 0) {
			f1 << "\\textbf{Methods} & ";
			for (int i = 0; i < firstRowLabel.size() - 1; i++) {
				f1 << "\\textbf{" << firstRowLabel[i] << "} &";
			}
			f1 << "\\textbf{" << firstRowLabel[firstRowLabel.size() - 1] << "}\\\\\\midrule[1pt]" << endl;
		}
		else {
			f1 << "\\textbf{Methods} & ";
			for (int i = 0; i < firstRowLabel.size() - 1; i++) {
				f1 << "\\multicolumn{" << subRowLabel.size() << "}{c}{\\textbf{" << firstRowLabel[i] << "}} &";
			}
			f1 << "\\multicolumn{" << subRowLabel.size() << "}{c}{\\textbf{" << firstRowLabel[firstRowLabel.size() - 1] << "}}\\\\" << endl;
			f1 << "\\textbf{Models} & ";
			for (int i = 0; i < firstRowLabel.size(); i++) {
				for (int j = 0; j < subRowLabel.size(); j++) {
					if (i == firstRowLabel.size() - 1 && j == subRowLabel.size() - 1) {
						f1 << subRowLabel[j] << " \\\\\\midrule[1pt] " << endl;
					}
					else {
						f1 << subRowLabel[j] << " & ";
					}
				}
			}
		}
		//2.写入数据
		if (subRowLabel.size() > 0) {
			for (int i = 0; i < data.size(); i++) {
				vector<float> data_i = data[i];
				vector<bool> label_i(data_i.size(), false);
				for (int j = 0; j < subRowLabel.size(); j++) {
					int laebl_ij_index_max = j;
					int laebl_ij_index_min = j;
					float extrmedata_max = data_i[j];
					float extrmedata_min = data_i[j];
					for (int k = j; k < data_i.size(); k = k + subRowLabel.size()) {
						if (data_i[k] > extrmedata_max) {
							extrmedata_max = data_i[k];
							laebl_ij_index_max = k;						
						}
						if (data_i[k] < extrmedata_min) {
							extrmedata_min = data_i[k];
							laebl_ij_index_min = k;						
						}
					}
					if (orderName == "Max") {
						label_i[laebl_ij_index_max] = true;
					}
					if (orderName == "Min") {
						label_i[laebl_ij_index_min] = true;
					}
				}
				f1 << "\\textbf{" << columnLabel[i] << "} & ";
				for (int j = 0; j < data_i.size() - 1; j++) {
					if (label_i[j]) {
						f1 << "\\textbf{"<<data_i[j] << "} & ";					
					}
					else {
						f1 << data_i[j] << " & ";					
					}				
				}
				f1 << data_i[data_i.size() - 1] << "\\\\" << endl;
			}
			f1 << "\\bottomrule[1pt] " << endl;
		
		}
		else {

			for (int i = 0; i < data.size(); i++) {

				vector<float> data_i = data[i];				
				int laebl_ij_index_max = 0;
				int laebl_ij_index_min = 0;
				float extrmedata_max = data_i[0];
				float extrmedata_min = data_i[0];

				for (int j = 0; j < data_i.size(); j++) {

					float data_ij = data_i[j];
					if (data_ij > extrmedata_max) {
						extrmedata_max = data_ij;
						laebl_ij_index_max = j;
					}
					if (data_ij < extrmedata_min) {
						extrmedata_min = data_ij;
						laebl_ij_index_min = j;
					}										
					
				}

				int label_p;
				if (orderName == "Max") {
					label_p = laebl_ij_index_max;
				}
				if (orderName == "Min") {
					label_p = laebl_ij_index_min;
				}

				f1 << "\\textbf{" << columnLabel[i] << "} & ";

				for (int j = 0; j < data_i.size() - 1; j++) {
					if (j == label_p) {
						f1 << "\\textbf{" << data_i[j] << "} & ";
					}
					else {
						f1 << data_i[j] << " & ";
					}
				}

				if (label_p == data_i.size() - 1) {
					f1 << "\\textbf{" << data_i[data_i.size() - 1] << "}\\\\" << endl;
				}
				else {
					f1 << data_i[data_i.size() - 1] << "\\\\" << endl;				
				}				
			}
			f1 << "\\bottomrule[1pt]" << endl;
		}
		
		//3.收尾
		f1 << "\\end{tabular}"<<endl;
		f1 << "\\label{T1}" << endl;
		f1 << "\\end{table*}" << endl;
		f1 << endl;
		f1.close();		
	
	}
};

调用LatexTable_init方法,传入txt文件的路径名字,就可以直接输出Latex表格代码。我写的比较粗糙,够我自己用的了。如果需要改数据类型,只要找到对应的位置,改变量即可。


三.生成结果

注:这里使用了包:\usepackage{booktabs}

\begin{table*}[]
\centering
\caption{caption for table.}
\begin{tabular}{c|ccccccccccccccc}\toprule[1pt]
\textbf{Methods} & \multicolumn{3}{c}{\textbf{Method1}} &\multicolumn{3}{c}{\textbf{Method2}} &\multicolumn{3}{c}{\textbf{Method3}} &\multicolumn{3}{c}{\textbf{Method4}} &\multicolumn{3}{c}{\textbf{Method5}}\\
\textbf{Models} & Q1 & Q2 & Q3 & Q1 & Q2 & Q3 & Q1 & Q2 & Q3 & Q1 & Q2 & Q3 & Q1 & Q2 & Q3 \\\midrule[1pt] 
\textbf{M1} & 1.2 & 1.1 & 1.4 & 5.6 & 5.3 & 5.6 & 2.2 & 3.1 & 0.4 & \textbf{15.6} & 25.3 & \textbf{45.6} & 11.2 & \textbf{51.1} & 21.4\\
\textbf{M2} & 0.2 & 0.1 & 0.4 & 15.6 & 15.3 & 15.6 & \textbf{72.2} & 33.1 & 0.4 & 65.6 & 125.3 & 145.6 & 1.2 & \textbf{351.1} & 221.4\\
\textbf{M3} & 21.1 & 31.1 & 51.4 & 75.6 & 95.3 & 25.6 & 22.2 & 23.1 & 20.4 & \textbf{215.6} & 225.3 & \textbf{245.6} & 211.2 & \textbf{251.1} & 221.4\\
\bottomrule[1pt] 
\end{tabular}
\label{T1}
\end{table*}

\begin{table*}[]
\centering
\caption{caption for table.}
\resizebox{\textwidth}{!}{
\begin{tabular}{c|ccccccccccccccc}\toprule[1pt]
\textbf{Methods} & \textbf{Method1} &\textbf{Method2} &\textbf{Method3} &\textbf{Method4} &\textbf{Method5} &\textbf{Method6} &\textbf{Method7} &\textbf{Method8} &\textbf{Method9} &\textbf{Method10} &\textbf{Method11} &\textbf{Method12} &\textbf{Method13} &\textbf{Method14} &\textbf{Method15}\\\midrule[1pt]
\textbf{M1} & 1.2 & 1.1 & 1.4 & 5.6 & 5.3 & 5.6 & 2.2 & 3.1 & 0.4 & 15.6 & 25.3 & 45.6 & 11.2 & \textbf{51.1} & 21.4\\
\textbf{M2} & 0.2 & 0.1 & 0.4 & 15.6 & 15.3 & 15.6 & 72.2 & 33.1 & 0.4 & 65.6 & 125.3 & 145.6 & 1.2 & \textbf{351.1} & 221.4\\
\textbf{M3} & 21.1 & 31.1 & 51.4 & 75.6 & 95.3 & 25.6 & 22.2 & 23.1 & 20.4 & 215.6 & 225.3 & 245.6 & 211.2 & \textbf{251.1} & 221.4\\
\bottomrule[1pt]
\end{tabular}}
\label{T1}
\end{table*}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿老甘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值