53

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

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

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

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

4

8 回答 8

75

或使用字符串流:

#include <sstream>
#include <iomanip>

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

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

于 2008-10-22T11:49:35.423 回答
17
char str[7];
snprintf (str, 7, "%06d", n);

snprintf

于 2008-10-22T11:36:58.337 回答
10

您可能需要注意的一件事是当您使用该stringstream方法时可能发生的潜在锁定。至少在 Visual Studio 2008 附带的 STL 中,由于在格式化过程中使用了各种语言环境信息,因此有许多锁被取出和释放。这可能对您来说是一个问题,也可能不是一个问题,具体取决于您有多少线程可能同时将数字转换为字符串......

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

我之所以注意到这一点,是因为我的工具最近吐出了“语言环境”锁,因为它是我的服务器系统中竞争最激烈的锁之一;这有点出人意料,可能会让我修改我一直在采取的方法(即sprintf从移回stringstream)......

于 2008-10-22T17:08:08.137 回答
4

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

int n = 999;
char buffer[256]; sprintf(buffer, "%06d", n);
string str(buffer);
于 2008-10-22T11:33:38.967 回答
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;
}
于 2008-10-22T12:25:18.830 回答
3

stringstream 会做(正如 xtofl 指出的那样)。Boost 格式是 snprintf 的更方便的替代品。

于 2008-10-22T11:55:35.367 回答
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 格式是解决这个问题的另一个工具:

#include <boost/format.hpp>

int n = 999;

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

Unfortunately, variable width specifier as arguments chained with the % operator are unsupported, this requires a format string setup (e.g. const std::string fmt = "%0" + std::to_string(6) + "d";).

In terms of performance, abseil and fmt claim to be very attractive and faster than boost. In any case, all three solutions should be more efficient than std::stringstream approaches, and other than the std::*printf family, they do not sacrifice type safety.

于 2018-07-12T14:16:50.300 回答
1

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

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

于 2008-10-22T11:33:58.997 回答