格式化带空格的字符串

时间:2013-08-23 08:36:14

标签: c++ string

我正在尝试用C ++创建一个优雅的日志系统。我目前正在使用printf(),但cout也可以选择。

我想要实现的是这样的

console_log( "ClassName", "funcName", "Message." );

我目前的代码是:

static void console_log( const std::string & className, const std::string & funcName, const std::string & message ) {
    printf( "%s : %s : %s\n",  className.c_str(), funcName.c_str(), message.c_str() );
}

打印得很好,就像这样

// For example:
console_log( "MenuPanel", "selectedThisButton", "Something happened." );
console_log( "MenuPanel", "selectedAnotherButton", "Another thing happened." );

// Output:
MenuPanel : selectedThisButton : Something happened.
MenuPanel : selectedAnotherButton : Another thing happened.

但是,我希望它以类似于表格的方式打印,其中所有“列”都正确对齐。例如:

MenuPanel : selectedThisButton    : Something happened.
MenuPanel : selectedAnotherButton : Another thing happened.

如何使第一个和第二个“列”具有完全相同的宽度/字符数,如果需要还有其他空格?它不需要是动态的。将“列”设置为16个字符就可以了。

我不希望使用任何第三方库来做这么简单的事情。如果可能,不要boost

3 个答案:

答案 0 :(得分:3)

我会使用I / O流而不是C风格printf,并且对于具有特定宽度的打印内容(任何类型),您可以包含<iomanip>并设置field width

some_stream << std::setw(MY_WIDTH) << whatever;

示例:

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::setw(10) << "hi";
}

输出:

        hi

答案 1 :(得分:2)

如果您准备好'保持简单'的方式可以替换:

printf( "%s : %s : %s\n", className.c_str(), funcName.c_str(), 
message.c_str() ); 

printf( "%30s : %30s : %30s\n", className.c_str(), funcName.c_str(), 
message.c_str() );

无论你喜欢什么样的宽度,你都可以查看printf文档中的对齐修饰符。

答案 2 :(得分:0)

一般的解决方案非常复杂,但如果你可以假设的话 固定宽度字体(每个字符具有相同的宽度), 并且知道前面每列的宽度,例如:

std::string rPad( std::string const& original, int minWidth )
{
    return original
        + std::string( 
            std::max( minWidth - static_cast<int>( original.size() ), 0 ),
            ' ' );
}

void console_log(
    std::string const& className,
    std::string const& funcName,
    std::string const& message )
{
    std::cout << rPad( className, classNameWidth )
        << " : " << rPad( funcName, funcNameWidth )
        << " : " << rPad
        << std::endl;
}

或者,您可以执行以下操作:

void console_log(
    std::string const& className,
    std::string const& funcName,
    std::string const& message )
{
    std::cout << alignedText( classNameWidth ) << className
        << " : " << alignedText( funcNameWidth ) << funcName
        << " : " << message << std::endl;
}

操纵者alignedText通常很有用,而你 无论如何应该在你的工具箱中拥有它:

class alignedText
{
    mutable std::ostream* myOwner;
    mutable std::ostream::fmtflags myFlags;
    int myWidth;
public:
    alignedText( int width ) : myOwner myWidth( width ) {}
    ~alignedText()
    {
        if ( myOwner != nullptr ) {
            myOwner->flags( myFlags );
        }
    }
    void set( std::ostream& dest ) const
    {
        if ( myOwner == nullptr ) {
            myOwner = &dest;
            myFlags = myOwner->flags();
        }
        dest.setf( std::ios_base::left, std::ios_base::adjustfield );
        dest.width( myWidth );
    }
    friend std::ostream& operator<<( std::ostream& dest, alignedText const& manip )
    {
        manip.set( dest );
        return dest;
    }
};

(虽然可以使用printf完成同样的事情,结果 是不太可读,完全不可维护,当然, 你的一般脆弱性为printf。)