C++中将数字转换为指定长度的字符串

问题描述 投票:0回答:10

我有一些不同长度的数字(如 1、999、76492 等),我想将它们全部转换为具有公共长度的字符串(例如,如果长度为 6,那么这些字符串将是: '000001 '、'000999'、'076492')。

换句话说,我需要在数字中添加正确数量的前导零。

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

C++中有这样的函数吗?

c++ integer stdstring
10个回答
82
投票

或使用字符串流:

#include <sstream>
#include <iomanip>

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

我整理了在 arachnoid.com 上找到的信息,因为我更喜欢 iostream 的类型安全方式。此外,您同样可以在任何其他输出流上使用此代码。


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

参见snprintf


13
投票

可能想要注意的一件事是,当您使用

stringstream
方法时可能会发生潜在的锁定。至少在 Visual Studio 2008 附带的 STL 中,由于格式化过程中使用了各种区域设置信息,因此取消和释放了许多锁。这对您来说可能是问题,也可能不是问题,具体取决于您有多少线程可能同时将数字转换为字符串......

sprintf
版本不采用任何锁(至少根据我目前正在开发的锁监控工具......),因此在并发情况下使用可能“更好”。

我之所以注意到这一点,是因为我的工具最近将“区域设置”锁吐出为我的服务器系统中竞争最激烈的锁之一;这有点令人惊讶,可能会让我修改我一直在采取的方法(即从

sprintf
回到
stringstream
)...


4
投票

有很多方法可以做到这一点。最简单的是:

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

4
投票

此方法不使用流或 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
投票

stringstream 就可以了(正如 xtofl 指出的那样)。 Boost 格式 是 snprintf 的更方便的替代品。


3
投票

这是一个旧线程,但由于 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)
是可能的。 boost format 是解决此问题的另一个工具:

#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
系列之外,它们不会牺牲类型安全性。


1
投票

sprintf 是类似 C 的方法,它也适用于 C++。

在 C++ 中,字符串流和流输出格式化的组合(请参阅 http://www.arachnoid.com/cpptutor/student3.html)即可完成这项工作。


0
投票

从 C++ 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;
}

0
投票

您可以使用 C++20 来完成

std::format
godbolt):

int n = 999;
std::string str = std::format("{:0{}}", n, 6);
// str == "000999"
© www.soinside.com 2019 - 2024. All rights reserved.