Преобразовать число в строку указанной длины в C ++ - PullRequest
42 голосов
/ 22 октября 2008

У меня есть несколько чисел разной длины (например, 1, 999, 76492 и т. Д.), И я хочу преобразовать их все в строки общей длины (например, если длина равна 6, то эти строки будут: «000001», «000999», «076492»).

Другими словами, мне нужно добавить правильное количество ведущих нулей к числу.

int n = 999;
string str = some_function(n,6);
//str = '000999'

Есть ли такая функция в C ++?

Ответы [ 8 ]

56 голосов
/ 22 октября 2008

или используя строковые потоки:

#include <sstream>
#include <iomanip>

std::stringstream ss;
ss << std::setw(10) << std::setfill('0') << i;
std::string s = ss.str();

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

13 голосов
/ 22 октября 2008
char str[7];
snprintf (str, 7, "%06d", n);

См. snprintf

8 голосов
/ 22 октября 2008

Одна вещь, о которой вы можете хотите знать, - это потенциальная блокировка, которая может возникнуть при использовании подхода stringstream. В STL, поставляемом с Visual Studio 2008, по крайней мере, есть много блокировок, снятых и выпущенных, поскольку различная информация о локали используется во время форматирования. Это может или не может быть проблемой для вас в зависимости от того, сколько у вас потоков, которые могут одновременно преобразовывать числа в строки ...

Версия sprintf не берет никаких блокировок (по крайней мере, в соответствии с инструментом мониторинга блокировок, который я сейчас разрабатываю ...) и поэтому может быть «лучше» для использования в параллельных ситуациях.

Я заметил это только потому, что мой инструмент недавно выплюнул блокировки 'locale' как одни из самых востребованных для блокировок в моей серверной системе; это стало неожиданностью и может заставить меня пересмотреть подход, который я использовал (то есть вернуться к sprintf от stringstream) ...

3 голосов
/ 22 октября 2008

Этот метод не использует ни потоки, ни sprintf. Помимо проблем с блокировкой, потоки снижают производительность и действительно являются излишним. Для потоков накладные расходы обусловлены необходимостью создания буфера пара и потока. Для sprintf издержки возникают из-за необходимости интерпретировать строку формата. Это работает, даже если n отрицательно или когда строковое представление n длиннее len . Это самое быстрое решение.

inline string some_function(int n, int len)
{
    string result(len--, '0');
    for (int val=(n<0)?-n:n; len>=0&&val!=0; --len,val/=10)
       result[len]='0'+val%10;
    if (len>=0&&n<0) result[0]='-';
    return result;
}
3 голосов
/ 22 октября 2008
Подойдет

stringstream (, как указал xtofl ). Boost format - более удобная замена snprintf.

2 голосов
/ 22 октября 2008

Есть много способов сделать это. Самый простой будет:

int n = 999;
char buffer[256]; sprintf(buffer, "%06d", n);
string str(buffer);
1 голос
/ 22 октября 2008

sprintf - это C-подобный способ сделать это, который также работает в C ++.

В C ++ сочетание строкового потока и форматирования выходного потока (см. http://www.arachnoid.com/cpptutor/student3.html) сделает работу.

0 голосов
/ 12 июля 2018

Это старая ветка, но поскольку fmt может сделать ее стандартной, вот дополнительное решение:

#include <fmt/format.h>

int n = 999;

const auto str = fmt::format("{:0>{}}", n, 6);

Обратите внимание, что fmt::format("{:0>6}", n) одинаково хорошо работает, когда желаемая ширина известна во время компиляции. Другой вариант: abseil :

#include <absl/strings/str_format.h>

int n = 999;

const auto str = absl::StrFormat("%0*d", 6, n);

Опять же, abs::StrFormat("%06d", n) возможно. расширенный формат - еще один инструмент для решения этой проблемы:

#include <boost/format.hpp>

int n = 999;

const auto str = boost::str(boost::format("%06d") % n);

К сожалению, спецификатор переменной ширины в качестве аргументов, связанных с оператором %, не поддерживается, для этого требуется настройка строки формата (например, const std::string fmt = "%0" + std::to_string(6) + "d";).

С точки зрения производительности, abseil и fmt утверждают, что они очень привлекательны и быстрее, чем boost. В любом случае все три решения должны быть более эффективными, чем std::stringstream подходы, и, кроме семейства std::*printf, они не приносят в жертву безопасность типов.

...