Преобразовать число в строку указанной длины в C++

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

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

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

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

9 ответов

Решение

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

#include <sstream>
#include <iomanip>

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

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

char str[7];
snprintf (str, 7, "%06d", n);

Смотрите snprintf

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

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

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

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

#include <fmt/format.h>

int n = 999;

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

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

#include <absl/strings/str_format.h>

int n = 999;

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

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

#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 семья, они не жертвуют типом безопасности.

Этот метод не использует ни потоки, ни 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;
}

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

int n = 999;
char buffer[256]; sprintf(buffer, "%06d", n);
string str(buffer);

stringstream сделает ( как указал xtofl). Boost формат - более удобная замена snprintf.

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

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

Из С++ 11 вы можете сделать:

       string to_string(unsigned int number, int length) {
    
    string num_str = std::to_string(number);
    
    if(num_str.length() >= length) return num_str;
    
    string leading_zeros(length - num_str.length(), '0');
    
    return leading_zeros + num_str;
}

Если вам также нужно обрабатывать отрицательные числа, вы можете переписать функцию, как показано ниже:

      string to_string(int number, int length) {
    
    string num_str = std::to_string(number);

    if(num_str.length() >= length) return num_str;

    string leading_zeros(length - num_str.length(), '0');
    
    //for negative numbers swap the leading zero with the leading negative sign
    if(num_str[0] == '-') {  
        num_str[0] = '0';
        leading_zeros[0] = '-';
    }

    return leading_zeros + num_str;
}
Другие вопросы по тегам