如何轻松地将数据表格式化为C++
How can I easily format my data table in C++?
我不确定,但我想我记得Java中有一些东西可以指定字符串或数字从窗口左侧开始的距离。
如何轻松格式化表格?我有这个(使用 setw(:
Bob Doe 10.96 7.61 14.39 2.11 47.30 14.21 44.58 5.00 60.23
Helen City 10.44 7.78 16.27 1.99 48.92 13.93 53.79 5.00 70.97
Joe Green 10.90 7.33 14.49 2.05 47.91 14.15 44.45 4.70 73.98
理想情况下希望:
Bob Doe BLR 10.96 7.61 14.39 2.11 47.30 14.21 44.58 5.00 60.23 4:27.47
Helen City CUB 10.90 7.33 14.49 2.05 47.91 14.15 44.45 4.70 73.98 4:29.17
Joe Green USA 10.44 7.78 16.27 1.99 48.92 13.93 53.79 5.00 70.97 5:06.59
计算是唯一的方法吗?还是有一些神奇甚至更简单的方法?
在C++中,您有三个函数来帮助您做您想做的事情。在 <iomanip>
.
中定义了 - setw(( 帮助你定义输出的宽度.
- setfill(( 用你想要的字符填充其余部分(在你的例子中 ''(.
- 左(或右(允许您定义对齐方式。
这是编写第一行的代码:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
const char separator = ' ';
const int nameWidth = 6;
const int numWidth = 8;
cout << left << setw(nameWidth) << setfill(separator) << "Bob";
cout << left << setw(nameWidth) << setfill(separator) << "Doe";
cout << left << setw(numWidth) << setfill(separator) << 10.96;
cout << left << setw(numWidth) << setfill(separator) << 7.61;
cout << left << setw(numWidth) << setfill(separator) << 14.39;
cout << left << setw(numWidth) << setfill(separator) << 2.11;
cout << left << setw(numWidth) << setfill(separator) << 47.30;
cout << left << setw(numWidth) << setfill(separator) << 14.21;
cout << left << setw(numWidth) << setfill(separator) << 44.58;
cout << left << setw(numWidth) << setfill(separator) << 5.00;
cout << left << setw(numWidth) << setfill(separator) << 60.23;
cout << endl;
cin.get();
}
编辑:要减少代码,您可以使用模板函数:
template<typename T> void printElement(T t, const int& width)
{
cout << left << setw(width) << setfill(separator) << t;
}
你可以这样使用:
printElement("Bob", nameWidth);
printElement("Doe", nameWidth);
printElement(10.96, numWidth);
printElement(17.61, numWidth);
printElement(14.39, numWidth);
printElement(2.11, numWidth);
printElement(47.30, numWidth);
printElement(14.21, numWidth);
printElement(44.58, numWidth);
printElement(5.00, numWidth);
printElement(60.23, numWidth);
cout << endl;
以下是我用来以有组织的表格形式显示数据的各种函数,以及一个演示可能使用场景的示例。
因为这些函数使用字符串流,所以它们不如其他解决方案快,但对我来说,这并不重要,---计算瓶颈在其他地方。
使用字符串流的一个优点是函数会更改其自身(内部作用域(字符串流的精度,而不是更改静态 cout 精度。 因此,您永远不必担心无意中修改精度,从而持续影响代码的其他部分。
显示任意精度
此prd
函数("打印双精度"的缩写(仅以指定的精度打印双精度值。
/* Convert double to string with specified number of places after the decimal. */
std::string prd(const double x, const int decDigits) {
stringstream ss;
ss << fixed;
ss.precision(decDigits); // set # places after decimal
ss << x;
return ss.str();
}
以下只是一个变体,允许您在数字左侧指定空格填充。 这在显示表时很有帮助。
/* Convert double to string with specified number of places after the decimal
and left padding. */
std::string prd(const double x, const int decDigits, const int width) {
stringstream ss;
ss << fixed << right;
ss.fill(' '); // fill space around displayed #
ss.width(width); // set width around displayed #
ss.precision(decDigits); // set # places after decimal
ss << x;
return ss.str();
}
居中对齐功能
此函数只是将文本居中对齐,用空格左右填充,直到返回的字符串与指定的宽度一样大。
/*! Center-aligns string within a field of width w. Pads with blank spaces
to enforce alignment. */
std::string center(const string s, const int w) {
stringstream ss, spaces;
int padding = w - s.size(); // count excess room to pad
for(int i=0; i<padding/2; ++i)
spaces << " ";
ss << spaces.str() << s << spaces.str(); // format with padding
if(padding>0 && padding%2!=0) // if odd #, add 1 space
ss << " ";
return ss.str();
}
表格输出示例
因此,我们可以使用上面的 prd
和 center
函数以以下方式输出表。
代码:
std::cout << center("x",10) << " | "
<< center("x^2",10) << " | "
<< center("(x^2)/8",10) << "n";
std::cout << std::string(10*3 + 2*3, '-') << "n";
for(double x=1.5; x<200; x +=x*2) {
std::cout << prd(x,1,10) << " | "
<< prd(x*x,2,10) << " | "
<< prd(x*x/8.0,4,10) << "n";
}
将打印表格:
x | x^2 | (x^2)/8
------------------------------------
1.5 | 2.25 | 0.2812
4.5 | 20.25 | 2.5312
13.5 | 182.25 | 22.7812
40.5 | 1640.25 | 205.0312
121.5 | 14762.25 | 1845.2812
右对齐和左对齐函数
当然,您可以轻松构造 center
函数的变体,这些变体可以右对齐或左对齐,并添加填充空格以填充所需的宽度。 以下是此类函数:
/* Right-aligns string within a field of width w. Pads with blank spaces
to enforce alignment. */
string right(const string s, const int w) {
stringstream ss, spaces;
int padding = w - s.size(); // count excess room to pad
for(int i=0; i<padding; ++i)
spaces << " ";
ss << spaces.str() << s; // format with padding
return ss.str();
}
/*! Left-aligns string within a field of width w. Pads with blank spaces
to enforce alignment. */
string left(const string s, const int w) {
stringstream ss, spaces;
int padding = w - s.size(); // count excess room to pad
for(int i=0; i<padding; ++i)
spaces << " ";
ss << s << spaces.str(); // format with padding
return ss.str();
}
我相信有很多更优雅的方法可以做这种事情---当然还有更简洁的方法。 但这就是我所做的。 对我来说效果很好。
只需将 sprintf 与格式说明符一起使用即可格式化字段。您还可以使用 MFC CString
#include <iostream>
#include "stdio.h"
using namespace std;
int main()
{
char buf[256];
char pattern[] = "%10s %10s %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f";
sprintf(buf, pattern, "Bob", "Doe", 10.96, 7.61, 14.39, 2.11, 47.30, 14.21, 44.58, 5.00, 60.23);
cout << buf << endl;
sprintf(buf, pattern, "Helen", "City", 10.44, 7.78, 16.27, 1.99, 48.92, 13.93, 53.79, 5.00, 70.97);
cout << buf << endl;
sprintf(buf, pattern, "Joe", "Green", 10.90, 7.33, 14.49, 2.05, 47.91, 14.15, 44.45, 4.70, 73.98);
cout << buf << endl;
}
你可以做这样的事情来简化这个过程。
#include <iomanip>
#include <iostream>
struct TableFormat {
int width;
char fill;
TableFormat(): width(14), fill(' ') {}
template<typename T>
TableFormat& operator<<(const T& data) {
std::cout << data << std::setw(width) << std::setfill(fill);
return *this;
}
TableFormat& operator<<(std::ostream&(*out)(std::ostream&)) {
std::cout << out;
return *this;
}
};
int main() {
TableFormat out;
out << "Bob" << "Doe";
out.width = 8;
out << "BLR" << 10.96 << 7.61 << 14.39 << 2.11 << 47.30;
}
这将打印出来(在我的情况下很糟糕,但它在一定程度上是"可定制的"(:
Bob Doe BLR 10.96 7.61 14.39 2.11 47.3
代码是不言自明的,它只是std::cout
的包装器,可以让您更轻松地进行繁琐的调用,operator<<
的第二个重载是允许您发送std::endl
..
> C++20 包含<format>
但目前 libc++ 不支持它.
我建议使用 {fmt} 库,因为它可以在 Ubuntu20 中轻松获得。
根据文档,您也可以将宽度指定为参数。
格式示例:{2:<{0}}
`2` -> Use second arg as value.
`:` -> Use non-default format.
`<` -> Align to left
`{0}` -> Use argument 0 as width.
现场演示
#include <string>
#include <iostream>
#include <fmt/core.h>
#include <tuple>
#include <vector>
int main()
{
using Row = std::tuple<std::string, std::string, double>;
std::vector<Row> table = {
std::make_tuple("Bob", "Doe", 10.96),
std::make_tuple("Helen", "City", 10.44),
std::make_tuple("Joe", "Green", 10.90)
};
size_t nameWidth{12};
size_t valWidth{7};
for(const auto& row: table){
std::cout << fmt::format("{2:<{0}} {3:<{0}} {4:<{1}} n",
nameWidth, valWidth, std::get<0>(row), std::get<1>(row), std::get<2>(row) );
}
}
输出
Bob Doe 10.96
Helen City 10.44
Joe Green 10.9
假设你想格式化你的输出,类似于一个表格,你需要的是I/O操纵器。
您可以使用 setw(( 操纵器来设置输出宽度,并使用 setfill(( 来设置填充字符。
考虑一个例子:
string firstname = "Bob";
string lastname = "Doe";
string country = "BLR";
float f1 = 10.96f, f2=7.61f, f3=14.39f, f4=2.11f, f5=47.30f, f6=14.21f, f7=44.58f, f8=5.00f, f9=60.23f;
string time = "4:27.47";
cout << setw(12) << firstname << set(12) << lastname;
cout << setw(5) << country << setprecision(2) << f1 << setprecision(2) << f2 << setprecision(2) << f3..
- 打印字符串时使用
setw()
设置宽度 - 使用
setprecision
设置浮点值的精度 - 阅读 MSDN
我不确定你写了什么,所以我看不出有什么问题,但你可以用 std::setw 得到你想要的结果:
#include <iostream>
#include <iomanip>
int main() {
std::cout << std::left << std::setw(20) << "BoB" << std::setw(20) << 123.456789 << 'n';
std::cout << std::left << std::setw(20) << "Richard" << std::setw(20) << 1.0 << 'n';
}
http://ideone.com/Iz5RXr
- C++格式化输出问题
- 格式化浮点值:返回默认值
- 自动格式化程序> >更改为>>
- 如何从C++中的格式化字符串派生整数?
- 将从格式化文本文件读取的文本数据存储到链表
- 在不使用系统的情况下从C++应用程序格式化 Linux 中的 SD 卡
- 高精度双精度的 Sprintf 格式化问题
- 如何在 c++ 中格式化和访问 2D 矢量数组中的数据
- 叮当格式化程序多行格式配置错误
- 如何格式化我的文本文件以使其不会一遍又一遍地重复同一行?
- 从函数(不抛出函数)返回异常以进行消息格式化?
- 从格式化输入操作中获取读取字符数
- 如何从标准输入中检测格式化输入错误?
- 无法从 spdlog 中格式化参数
- 格式化时间 c++ dd/mm/yyyy hh:ss.
- 如何正确格式化csv文件?
- 格式化sqlite3_exec结果
- 使用 std::locale 格式化法语数字时无效的 UTF-8 数据
- C++逐步格式化字符串
- 如何使用 clang 格式格式化地图初始化?