Как отформатировать текст с помощью std:out setfill std::setw std:right с одним пробелом

Я просто хочу отформатировать строку и целочисленное значение с правильным выравниванием. Нет проблем сделать это без начального пробела перед целочисленным значением.

bytes.....................123981
total bytes..............1030131 

Но это должно выглядеть так:

bytes ................... 123981
total bytes ............ 1030131

К сожалению, приведенный ниже пример не будет работать, потому что setw (выравнивание по правому краю) относится только к следующему элементу потока.

int iBytes = 123981;
int iTotalBytes = 1030131;
cout << setfill('.');
cout << right;
cout << "bytes " << setw(20) << " " << iBytes << endl;
cout << "total bytes " << setw(14) << " " << iTotalBytes << endl;

Я почти никогда не использую std::cout, поэтому есть ли простой способ сделать это без предварительного присоединения пробела к значению?


person seizu    schedule 16.11.2014    source источник


Ответы (2)


Самым простым способом было бы записать ваш " " и значение в std::stringstream и записать полученный результат str() в ваш выходной поток, например:

std::stringstream ss;
ss << " " << iBytes;
cout << "bytes " << setw(20) << ss.str() << endl;

А тут полный перебор. Префикс шаблонного класса, который можно распечатать, объединяет два аргумента конструктора prefix,val в одну строку для печати. числовой формат, а точность берется из конечного выходного потока. Работает с целыми числами, числами с плавающей запятой, строками и константными символами *. И должен работать с каждым аргументом, имеющим допустимый оператор вывода.

#include <fstream> 
#include <iostream> 
#include <iomanip> 
#include <sstream> 

using  namespace std; 

template<class T> 
class prefixed_base  { 
public: 
    prefixed_base(const std::string & prefix,const T val) : _p(prefix),_t(val) { 
    } 
protected: 
    std::string _p; 
    T           _t; 
}; 

// Specialization for const char *
template<> 
class prefixed_base<const char*>  { 
public: 
    prefixed_base(const std::string & prefix,const char * val) : _p(prefix),_t(val) { 
    } 
protected: 
    std::string _p; 
    std::string _t; 
}; 

template<class T> 
class prefixed : public  prefixed_base<T> { 
private: 
    typedef prefixed_base<T> super; 
public: 
    prefixed(const std::string & prefix,const T val) : super(prefix,val) { 
    } 

    // Output the prefixed value to an ostream
    // Write into a stringstream and copy most of the
    // formats from os.

    std::ostream & operator()(std::ostream & os) const { 
        std::stringstream ss; 

        // We 'inherit' all formats from the 
        // target stream except with. This Way we 
        // keep informations like hex,dec,fixed,precision 

        ss.copyfmt(os); 
        ss << std::setw(0); 
        ss << super::_p; 

        ss.copyfmt(os); 
        ss << std::setw(0); 
        ss << super::_t; 

        return os << ss.str(); 
    } 
}; 

// Output operator for class prefixed
template<class T> 
std::ostream & operator<<(std::ostream & os,const prefixed<T> & p) { 
    return p(os); 
} 

// This function can be used directly for output like os << with_prefix(" ",33.3)
template<class T> 
prefixed<T>    with_prefix(const std::string & p,const T  v) { 
    return prefixed<T>(p,v); 
} 

int main() { 
    int iBytes = 123981; 
    int iTotalBytes = 1030131; 
    cout << setfill('.'); 
    cout << right; 

    cout << "bytes " << setw(20) << with_prefix(" ",iBytes) << endl; 
    cout << "total bytes " << setw(14) << with_prefix(" ",iTotalBytes) << endl; 

    cout << "bla#1 "       << setw(20) <<  std::fixed << std::setprecision(9) << with_prefix(" ",220.55)      << endl; 
    cout << "blablabla#2 " << setw(14) <<  std::hex << with_prefix(" ",iTotalBytes) << endl; 
} 
person Oncaphillis    schedule 16.11.2014
comment
Спасибо за ваш вклад, хотя я опасался, что другого выхода нет. Если никто не предложит идею (с меньшим излишеством), думаю, я приму ваше решение. Я забыл упомянуть, что мне нужна поддержка UNICODE, но это не проблема. - person seizu; 17.11.2014
comment
@seizu, это потребовало бы еще большей магии шаблонов. Превращение ostream в basic_ostream‹C› и строку в basic_string‹C› и т. д. или просто используйте простое решение stringstream. - person Oncaphillis; 17.11.2014

@Oncaphillis, спасибо за исходный код, я немного адаптирую его для своих нужд. Я только что написал функцию для преобразования значений. std::to_string используется стандартом C++11, поэтому вместо этого я решил использовать _to_string/_to_wstring. Сложность заключалась в том, чтобы заставить wcout работать с UNICODE на консоли Windows. У меня не очень получилось, поэтому пришлось искать обходной путь. В любом случае, чтобы напечатать, например. Символы кириллицы, вы должны изменить шрифт консоли на Consolas или Lucida.

#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <iomanip>
#include <sstream>

using namespace std;

#if defined(UNICODE) || defined(_UNICODE)

    #define _tcout std::wcout
    #define _to_tstring _to_wstring

    template <typename T>std::wstring _to_wstring(const T& value) {
        std::wostringstream wos;
        wos.copyfmt(std::wcout);
        wos << value;
        return wos.str();
    }
#else
    #define _tcout std::cout
    #define _to_tstring _to_string

    template <typename T> std::string _to_string(const T& value) {
        std::ostringstream os;
        os.copyfmt(std::cout);
        os << value;
        return os.str();
    }
#endif

int _tmain(int argc, _TCHAR* argv[]) {
    int iBytes = 123981; 
    int iTotalBytes = 1030131; 

#if defined(UNICODE) || defined(_UNICODE)
    wostringstream  newCoutBuffer;
    wstreambuf*     oldCoutBuffer = _tcout.rdbuf(newCoutBuffer.rdbuf()); // redirect cout buffer
#endif

    _tcout.imbue(std::locale("German"));  // enable thousand separator
    _tcout.precision(0);
    _tcout << setfill(_T('.')) << right << fixed;

    _tcout << _T("bytes ")          << setw(20) << _T(" ") + _to_tstring(iBytes) << endl;
    _tcout << _T("bytes total ")    << setw(14) << _T(" ") + _to_tstring(iTotalBytes) << endl;
    _tcout << _T("bla bla ")        << fixed << setprecision(9); _tcout << setw(18) << _T(" ") +  _to_tstring(0.1337) << endl; 
    _tcout << _T("Милые женщины ")  << hex; _tcout << setw(12) << _T(" ") +  _to_tstring(iTotalBytes) << endl; 
    _tcout << _T("retries ")        << dec; _tcout << setw(18) << _T(" ") + _to_tstring(2) + _T(" of ") +  _to_tstring(20) << endl; 

#if defined(UNICODE) || defined(_UNICODE)
    DWORD dwWritten;
    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), newCoutBuffer.str().c_str(),newCoutBuffer.tellp(),&dwWritten,NULL);
    _tcout.rdbuf(oldCoutBuffer);
#endif

    return 0;
}

Выход:

bytes ............ 123.981
bytes total .... 1.030.131
bla bla ...... 0,133700000
Милые женщины ..... fb.7f3
retries .......... 2 of 20
person seizu    schedule 21.11.2014