Reputation: 1055
I'm not sure, but I think I remember there being something in Java that can specify how far from the left of a window that a string or digit begins..
How to easily format a table? I have this (using 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
and ideally would like:
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
Is the only way calculations? Or is there some magical even more simple way?
Upvotes: 43
Views: 143507
Reputation: 2578
C++20 includes <format>
but it's not supported by libc++ for now.
I suggest to use {fmt} library since it could be obtained easily in Ubuntu20.
According to the doc, you may specify the width as an argument as well.
Format example: {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) );
}
}
Output
Bob Doe 10.96
Helen City 10.44
Joe Green 10.9
Upvotes: 1
Reputation: 2629
In C++, you have three functions to help you do what you want. There are defined in <iomanip>
.
- setw() helps you defined the width of the output.
- setfill() Fill the rest with the character you want (in your case ' ').
- left (or right) allow you to define the alignment.
Here is the code to write your first line :
#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();
}
EDIT :
To reduce the code, you can use a template function :
template<typename T> void printElement(T t, const int& width)
{
cout << left << setw(width) << setfill(separator) << t;
}
That you can use like this :
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;
Upvotes: 70
Reputation: 9499
Here are the various functions I use to display data in an organized, tabular form, along with an example demonstrating a possible use scenario.
Because the functions use stringstreams, they aren't as fast as other solutions, but for me that never matters --- the computing bottlekneck is elsewhere.
One advantage of using stringstreams is that the functions alter the precision of their own (internal scope) stringstreams, instead of changing the static cout precision. So you never have to worry about unintentionally modifying precision in a way that persists to affect other parts of your code.
DISPLAYING ARBITRARY PRECISION
This prd
function (short for "print double") simply prints a double value with a specified precision.
/* 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();
}
The following is just a variant that allows you to specify a blank-space padding to the left of the number. This can be helpful in displaying tables.
/* 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-ALIGN FUNCTION
This function simply center-aligns text, padding left and right with blank spaces until the returned string is as large as the specified width.
/*! 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();
}
EXAMPLE OF TABULAR OUTPUT
So, we could use the prd
and center
functions above to output a table in the following fashion.
The code:
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";
}
will print the table:
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
RIGHT- and LEFT-ALIGN FUNCTIONS
And, of course, you can easily construct variants of the center
function that right- or left-align and add padding spaces to fill the desired width. Here are such functions:
/* 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();
}
I'm sure there are plenty of more-elegant ways to do this kind of thing --- certainly there are more concise ways. But this is what I do. Works well for me.
Upvotes: 24
Reputation: 432
Just use sprintf with format specifiers to format fields. You can also use 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;
}
Upvotes: 3
Reputation: 88155
I'm not sure what you wrote so I can't see what's wrong, but you can get the results you want with 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';
}
Upvotes: 0
Reputation: 25695
Considering an example:
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()
to set the width while printing a stringsetprecision
to set the precision for floating valuesUpvotes: 0
Reputation: 21317
You could do something like this to simplify the process a bit.
#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;
}
Which would print out (horribly in my case, but it's "customisable" to a degree):
Bob Doe BLR 10.96 7.61 14.39 2.11 47.3
The code is pretty self-explanatory, it's just a wrapper around std::cout
to allow you to make the tedious calls easier, the second overload for operator<<
is to allow you send std::endl
..
Upvotes: 2
Reputation: 206518
Assuming you want to format your output to resemble a table, what you need is I/O manipulators.
You can use setw() manipulator to set the output width and setfill() to set the filling character.
Upvotes: 0