Я рефакторинг некоторого устаревшего кода, который использует printf
со строками long (без какого-либо фактического форматирования) для печати заголовков таблицы в виде простого текста, которые условно выглядят так:
| Table | Column | Header |
которые в настоящее время производятся так:
printf("| Table | Column | Header |");
Я хотел бы произвести выше с кодом для эффекта1:
outputStream << "|" << std::setw(10) << std::center << "Table"<< "|" << std::setw(10) << std::center << "Column"<< "|" << std::setw(9) << std::center << "Header"<< "|" << std::endl;
который не компилируется, потому что <iomanip>
имеет ручные манипуляторы std::left
, std::right
а также std::internal
, но, похоже, не имеет каких-либо std::center
, Есть ли чистый способ сделать это уже в стандартных библиотеках C ++, или мне придется вручную вычислять необходимый интервал?
1Несмотря на то, что это более многословно, чем код C, в долгосрочной перспективе он будет менее многословным из-за количества printf
заявления и количество вставленных дубликатов в их строках. Это также будет более расширяемым и обслуживаемым.
Вот вспомогательный класс, который выполняет то, что вы хотите:
#include <string>
#include <iostream>
#include <iomanip>
template<typename charT, typename traits = std::char_traits<charT> >
class center_helper {
std::basic_string<charT, traits> str_;
public:
center_helper(std::basic_string<charT, traits> str) : str_(str) {}
template<typename a, typename b>
friend std::basic_ostream<a, b>& operator<<(std::basic_ostream<a, b>& s, const center_helper<a, b>& c);
};
template<typename charT, typename traits = std::char_traits<charT> >
center_helper<charT, traits> centered(std::basic_string<charT, traits> str) {
return center_helper<charT, traits>(str);
}
// redeclare for std::string directly so we can support anything that implicitly converts to std::string
center_helper<std::string::value_type, std::string::traits_type> centered(const std::string& str) {
return center_helper<std::string::value_type, std::string::traits_type>(str);
}
template<typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& s, const center_helper<charT, traits>& c) {
std::streamsize w = s.width();
if (w > c.str_.length()) {
std::streamsize left = (w + c.str_.length()) / 2;
s.width(left);
s << c.str_;
s.width(w - left);
s << "";
} else {
s << c.str_;
}
return s;
}
Используется просто по телефону centered("String")
, вот так:
int main(int argc, char *argv[]) {
std::cout << "|" << std::setw(10) << centered("Table")
<< "|" << std::setw(10) << centered("Column")
<< "|" << std::setw(9) << centered("Header") << "|"<< std::endl;
}
Здесь нет std::center
Манипулятор. Боюсь, ты должен сделать это сам. Вы можете написать вспомогательную функцию для вычисления пробелов с учетом ширины и строки, чтобы уменьшить усилия.
Вот пример того, как может выглядеть вспомогательная функция. Нужна некоторая работа, чтобы сделать ее более эффективной и т. Д.
string helper(int width, const string& str) {
int len = str.length();
if(width < len) { return str; }
int diff = width - len;
int pad1 = diff/2;
int pad2 = diff - pad1;
return string(pad1, ' ') + str + string(pad2, ' ');
}
Боюсь, вам придется сделать это вручную. Но это не так
тяжело если ты работаешь со струнами. Что-то вроде:
std::string
centered( std::string const& original, int targetSize )
{
assert( targetSize >= 0 );
int padding = targetSize - checked_cast<int>( original.size() );
return padding > 0
? std::string( padding / 2, ' ' )
+ original
+ std::string( targetSize - (padding / 2), ' ' )
: original;
}
должен сделать свое дело.
вы могли бы использовать библиотеку NCURSES … это своего рода фанк, и вы должны добавить «-L NCURSES» к вашей команде компиляции (g ++ -L NCURSES yourProgram.cpp), и она будет работать, плюс вы можете делать цвета и другие «крутые» вещи [круто для CLI в любом случае].
просто прочитайте руководство, центрирование довольно легко.
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/