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

У меня есть 8 целых чисел цифры, которые я хотел бы распечатать отформатированный как это:

XXX-XX-XXX

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

Что хороший путь состоит в том, чтобы сделать это?

10
задан neuromancer 12 May 2010 в 02:13
поделиться

9 ответов

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

#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, "-");
};
11
ответ дан 3 December 2019 в 14:52
поделиться

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

Параметр формата здесь - «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;
}
6
ответ дан 3 December 2019 в 14:52
поделиться

Вы можете использовать класс 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
}
3
ответ дан 3 December 2019 в 14:52
поделиться

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

#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

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

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

5
ответ дан 3 December 2019 в 14:52
поделиться
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

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

1
ответ дан 3 December 2019 в 14:52
поделиться
#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;
}
1
ответ дан 3 December 2019 в 14:52
поделиться

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

char * formatter(int i)
{    
  char *buf = malloc(11*sizeof(char));
  sprintf(buf, "%03d-%02d-%03d", i/100000, (i/1000)%100, i%1000);
  return buf;
}
0
ответ дан 3 December 2019 в 14:52
поделиться

Как вам это?

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();
}

Edit 1: Я вижу, что strstream устарел и заменен на stringstream.

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

1
ответ дан 3 December 2019 в 14:52
поделиться

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

#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

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

4
ответ дан 3 December 2019 в 14:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: