Форматирование вывода консоли С++
Я пытаюсь отформатировать вывод на консоль в течение самого долгого времени, и ничего не происходит. Я пытаюсь использовать как можно больше iomanip
и функции ofstream&
out.
void list::displayByName(ostream& out) const
{
node *current_node = headByName;
// I have these outside the loop so I dont write it everytime.
out << "Name\t\t" << "\tLocation" << "\tRating " << "Acre" << endl;
out << "----\t\t" << "\t--------" << "\t------ " << "----" << endl;
while ( current_node )
{
out << current_node->item.getName()// equivalent tabs dont work?
<< current_node->item.getLocation()
<< current_node->item.getAcres()
<< current_node->item.getRating()
<< endl;
current_node = current_node->nextByName;
}
// The equivalent tabs do not work because I am writing names,
// each of different length to the console. That explains why they
// are not all evenly spaced apart.
}
Это их все, что я могу использовать, чтобы все это было правильно выровнено друг с другом?
Функции, которые я вызываю, понятны и имеют разные длины, поэтому они не очень хорошо выравниваются друг с другом.
Я пробовал почти все в iomanip
.
Ответы
Ответ 1
Вы можете написать процедуру, которая всегда печатает одинаковое количество символов в стандартном выходе.
что-то вроде
string StringPadding(string original, size_t charCount )
{
original.resize( charCount, ' ' );
return original;
}
а затем используйте это в своей программе
void list::displayByName(ostream& out) const
{
node *current_node = headByName;
out << StringPadding( "Name", 30 )
<< StringPadding( "Location", 10 )
<< StringPadding( "Rating", 10 )
<< StringPadding( "Acre", 10 ) << endl;
out << StringPadding( "----", 30 )
<< StringPadding( "--------", 10 )
<< StringPadding( "------", 10 )
<< StringPadding( "----", 10 ) << endl;
while ( current_node )
{
out << StringPadding( current_node->item.getName(), 30 )
<< StringPadding( current_node->item.getLocation(), 10 )
<< StringPadding( current_node->item.getRating(), 10 )
<< StringPadding( current_node->item.getAcres(), 10 )
<< endl;
current_node = current_node->nextByName;
}
}
Ответ 2
Подумайте об этом, используя Microsoft Excel:)
Вы думаете о своем потоке как о поле. Поэтому вы сначала устанавливаете ширину поля, затем вставляете текст в это поле. Например:
#include <iostream>
#include <iomanip>
#include <string>
int main()
{
using namespace std;
string firstName = "firstName",
secondName = "SecondName",
n = "Just stupid Text";
size_t fieldWidth = n.size(); // length of longest text
cout << setw(fieldWidth) << left << firstName << endl // left padding
<< setw(fieldWidth) << left << secondName << endl
<< setw(fieldWidth) << left << n << endl;
cout << setw(fieldWidth) << right << firstName << endl // right padding
<< setw(fieldWidth) << right << secondName << endl
<< setw(fieldWidth) << right << n << endl;
}
......
![alt text]()
......
Ширина поля означает только ширину text + spaces
. Вы могли бы fill
ничего, кроме пробелов:
string name = "My first name";
cout << setfill('_') << setw(name.size() + 10) << left << name;
.....
output::
My first name__________
......
Я думаю, что лучший способ - разобраться в вашем формате, напишите новый форматтер, который сделает все, что вам нужно:
#include <iostream>
#include <iomanip>
#include <string>
std::ostream& field(std::ostream& o)
{
// usually the console is 80-character wide.
// divide the line into four fields.
return o << std::setw(20) << std::right;
}
int main()
{
using namespace std;
string firstName = "firstName",
secondName = "SecondName",
n = "Just stupid Text";
size_t fieldWidth = n.size();
cout << field << firstName << endl
<< field << secondName << endl
<< field << n << endl;
}
Если вы начали думать о параметризованных манипуляторах, только те, которые принимают один параметр int
или long
, легко реализовать, другие типы действительно неясны, если вы не знакомы с потоками в C++
.
Ответ 3
Boost имеет библиотеку форматов, которая позволяет вам легко форматировать нашput, как старый C printf(), но с безопасностью типа С++.
Помните, что старый C printf() позволил вам указать ширину поля. Это пространство заполняет поле, если выходной сигнал меньше (обратите внимание, что он не справляется с полями большого размера).
#include <iostream>
#include <iomanip>
#include <boost/format.hpp>
struct X
{ // this structure reverse engineered from
// example provided by 'Mikael Jansson' in order to make this a running example
char* name;
double mean;
int sample_count;
};
int main()
{
X stats[] = {{"Plop",5.6,2}};
// nonsense output, just to exemplify
// stdio version
fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
stats, stats->name, stats->mean, stats->sample_count);
// iostream
std::cerr << "at " << (void*)stats << "/" << stats->name
<< ": mean value " << std::fixed << std::setprecision(3) << stats->mean
<< " of " << std::setw(4) << std::setfill(' ') << stats->sample_count
<< " samples\n";
// iostream with boost::format
std::cerr << boost::format("at %p/%s: mean value %.3f of %4d samples\n")
% stats % stats->name % stats->mean % stats->sample_count;
}
Ответ 4
Откажитесь от вкладок. Вы должны иметь возможность использовать io-манипуляторы для установки ширины поля, символа заполнения и флага формата (чтобы получить право налево или вправо). Используйте те же значения для заголовков, что и для данных, и все должно получиться красиво.
Также будьте осторожны, что вы переключили Rating и Acres в свой пример.