2013-08-23 4 views
0

Я пытаюсь создать элегантную систему ведения журнала на 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.

+5

«элегантный система каротажа в C++ "должна быть единственным самым вновь изобретенным колесом. –

+1

Как вы хотите исправить ширину? Если он жестко запрограммирован, вы можете просто добавить столько пробелов, сколько вам нужно, после вычисления длины строки. – ChronoTrigger

+2

Даже попытка этой простой задачи подсчета не дает мне достаточного доказательства того, что вопрос должен быть закрыт. О, и ['printf'] (http://linux.die.net/man/3/printf) имеет операторов выравнивания, если нужно прочитать справочную страницу (например,' printf («% -16s», ...); '). –

ответ

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 документацию для модификаторов выравнивания.

+0

Конечно, это не так формально, как он хочет. Встроенный язык, используемый 'printf', не является простым. –

+0

ну, я начал программировать язык C намного раньше, чем cout появляется =) и printf не так уж сложно .. сравните, например, такие вещи как: printf ("(% 0.10X)% 0.10X% s \ n", threadId, objectId , сообщение) .. с количеством кода, который вам нужен для cout – evilruff

3

Я хотел бы использовать потоки ввода-вывода/вместо 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 
+0

Есть ли причина, по которой вы предпочитаете потоки ввода-вывода над 'printf()'? – alxcyl

+2

@LanceGray: всегда лучше предпочесть то, что предлагает стандартная библиотека по старым решениям стиля C, которые некоторые могут найти «ужасно» :) – LihO

+0

+1, поскольку вопрос отмечен 'C++', а не потому, что '' должен быть лучше потому что он находится в стандартной библиотеке. – rubenvb

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.)

Смежные вопросы