Форматирование целого числа в С++

У меня есть 8-значное целое число, которое я хотел бы напечатать следующим образом:

XXX-XX-XXX

Я хотел бы использовать функцию, которая принимает int и возвращает строку.

Какой хороший способ сделать это?

Ответ 1

Вот как я это сделаю, лично. Возможно, это не самый быстрый способ решения проблемы, и определенно не такой, который можно было бы использовать в качестве функции эрунина, но мне это кажется чистым и понятным. Я брошу его на ринг в качестве альтернативы решениям mathier и loopier.

#include <sstream>
#include <string>
#include <iomanip>

std::string format(long num) {
  std::ostringstream oss;
  oss << std::setfill('0') << std::setw(8) << num;
  return oss.str().insert(3, "-").insert(6, "-");
};

Ответ 2

Протестировано, оно работает.

Параметр format здесь - "XXX-XX-XXX", но он только смотрит (и пропускает) тире.

std::string foo(char *format, long num)
{
    std::string s(format);

    if (num < 0) { return "Input must be positive"; }

    for (int nPos = s.length() - 1; nPos >= 0; --nPos)
    {
        if (s.at(nPos) == '-') continue;

        s.at(nPos) = '0' + (num % 10);
        num = num / 10;
    }

    if (num > 0) { return "Input too large for format string"; }

    return s;
}

Использование:

int main()
{
    printf(foo("###-##-###", 12345678).c_str());

    return 0;
}

Ответ 3

Здесь немного другой способ, который пытается работать со стандартной библиотекой и заставить ее выполнять большую часть реальной работы:

#include <locale>

template <class T>
struct formatter : std::numpunct<T> {
protected:
    T do_thousands_sep() const { return T('-'); }
    std::basic_string<T> do_grouping() const {
        return std::basic_string<T>("\3\2\3");
    }
};

#ifdef TEST

#include <iostream>

int main() {
    std::locale fmt(std::locale::classic(), new formatter<char>);   
    std::cout.imbue(fmt);

    std::cout << 12345678 << std::endl;
    return 0;
}

#endif

Чтобы вернуть строку, просто напишите в строковый поток и верните его .str().

Это может быть излишним, если вы хотите распечатать один номер таким образом, но если вы хотите делать подобные вещи в нескольких местах (или, особенно, если вы хотите отформатировать все числа, идущие к определенному поток таким образом) становится более разумным.

Ответ 4

Вот полная программа, которая показывает, как я это сделаю:

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

std::string formatInt (unsigned int i) {
    std::stringstream s;
    s << std::setfill('0') << std::setw(3) << ((i % 100000000) / 100000) << '-'
      << std::setfill('0') << std::setw(2) << ((i % 100000) / 1000) << '-'
      << std::setfill('0') << std::setw(3) << (i % 1000);
    return s.str();
}

int main (int argc, char *argv[]) {
    if (argc > 1)
        std::cout << formatInt (atoi (argv[1])) << std::endl;
    else
        std::cout << "Provide an argument, ya goose!" << std::endl;
    return 0;
}

Запуск этого с помощью определенных входов дает:

Input        Output
--------     ----------
12345678     123-45-678
0            000-00-000
7012         000-07-012
10101010     101-01-010
123456789    234-56-789
-7           949-67-289

Те последние два показывают важность тестирования. Если вам нужно другое поведение, вам нужно будет изменить код. Я вообще выбираю молчаливое применение правил, если вызывающий не может быть обеспокоен (или слишком глуп), чтобы следовать им, но, по-видимому, некоторым людям нравится использовать принцип наименьшего удивления и вызывать исключение: -)

Ответ 5

Вы можете использовать класс std:: ostringstream для преобразования числа в строку. Затем вы можете использовать строку цифр и печатать их, используя любое форматирование, которое вы хотите, как в следующем коде:

std::ostringstream oss;
oss << std::setfill('0') << std::setw(8) << number;
std::string str = oss.str();
if ( str.length() != 8 ){
    // some form of handling
}else{
    // print digits formatted as desired
}

Ответ 6

int your_number = 12345678;

std::cout << (your_number/10000000) % 10 << (your_number/1000000) % 10 << (your_number/100000) %10 << "-" << (your_number/10000) %10 << (your_number/1000) %10 << "-" << (your_number/100) %10 << (your_number/10) %10 << (your_number) %10;

http://www.ideone.com/17eRv

Это не функция, а ее общий метод для разбора числа int по числу.

Ответ 7

Как это?

std::string format(int x)
{
    std::stringstream ss

    ss.fill('0');
    ss.width(3);
    ss << (x / 10000);

    ss.width(1);
    ss << "-";

    ss.width(2);
    ss << (x / 1000) % 100;

    ss.width(1);
    ss << "-";

    ss.width(3);
    ss << x % 1000;

    return ss.str();
}

Изменить 1: я вижу, что streamstream устарел и заменен на stringstream.

Изменить 2: Исправлена ​​ошибка отсутствия ведущих 0. Я знаю, это уродливо.

Ответ 8

#include <iostream>
#include <string>

using namespace std;

template<class Int, class Bi>
void format(Int n, Bi first, Bi last)
{
    if( first == last ) return;
    while( n != 0 ) {
        Int t(n % 10);
        n /= 10;
        while( *--last != 'X' && last != first);
        *last = t + '0';
    }
}

int main(int argc, char* argv[])
{
    int i = 23462345;
    string s("XXX-XX-XXX");
    format(i, s.begin(), s.end());
    cout << s << endl;
    return 0;
}

Ответ 9

Очевидно, a char *, а не a string, но вы получите эту идею. Вам нужно будет освободить выход, как только вы закончите, и вы, вероятно, должны добавить проверку ошибок, но это должно сделать это:

char * formatter(int i)
{    
  char *buf = malloc(11*sizeof(char));
  sprintf(buf, "%03d-%02d-%03d", i/100000, (i/1000)%100, i%1000);
  return buf;
}

Ответ 10

Вам не требуется malloc или new, просто определите buf как char buff[11];