C++Win32通过to_wstring将零填充为int



我正在努力学习C++Win32。我为游戏环境创建了一个计时器类。典型的游戏计时器,它运行良好。我有这个功能,我想显示当前的游戏时间。

std::wstring Time::DisplayGameTime()
{
std::wstring Label = L"Current Time: ";
std::wstring daysText = L" " + std::to_wstring(Days()); //Returns int
std::wstring monthsText = L", " + std::to_wstring(Months()); //Returns int
std::wstring yearsText = L", " + std::to_wstring(Years()); // Returns int
std::wstring hoursText = L" " + std::to_wstring(Hours()); // Returns int
std::wstring minutesText = L" : " + std::to_wstring(Minutes()); // Returns int
std::wstring message = Label + daysText + monthsText + yearsText + hoursText + minutesText;
return message;
}

这也很好,除了分钟整数只打印一个数字,直到它达到10。我想在它上面加一个前导零,就像你在普通时钟上看到的那样。由于我使用的是std::to_wstring,所以我不能像在swprintf_s缓冲区中那样使用格式说明符。我试图弄清楚如何使用wstringstream,但我所尝试的都没有奏效。

目标是稍后使用此函数转换为LPCWSTR,以便DrawText显示在窗口中。

您可以使用传统的命令行"暴力";解决方法:

int DaysVal = Days();
std::wstring W = (DaysVal < 10 ? L"0" : L"") + std::to_wstring(DaysVal);

或者。。将std::stringstreamstd::setwstd::setfill一起使用(来自<iomanip>(。

std::wstringstream WS;
WS << std::setw(2) << std::setfill(L'0') << Days();
std::wstring W = WS.str();

PS:<iomanip>的功能也适用于std::cout和其他流,因此std::(w)stringstream在I/O方面是不必要的!

编辑:如果有人正在寻找利用snprintf():的解决方案

char CB[128];
std::snprintf(CB, sizeof(CB), "%.*i", NumDigits, Num);

使用精度(%.*i(优于使用宽度(%*i(,因为第二个运算的是字符总数,而不是位数!

编辑(2(:为了经得起未来的考验,我还包括了一个使用std::format():的解决方案

我已经很久没有玩{fmt}了,所以我不知道如何获得与printf()相同的结果。目前,它应该足够了(但预计负数少一位数(:

std::wstring W = fmt::format(L"{:+0{}}", Num, NumDigits);

将输出写入std::wstringstream对象与写入std::wcout流非常相似;您使用连续呼叫<<操作员;然后,完成后,可以使用.str()成员函数获得底层wstring对象的副本。

您可以使用std::setwstd::setfill函数分别控制每个字段的宽度和填充字符——如果需要,您可以在要调整输出的每个字段之前调用这些函数。

在您的情况下,您可以对所有字段使用默认格式,但最后一个字段除外,您可以将宽度设置为2,将填充字符设置为L'0':

#include <sstream>
#include <string>
#include <iomanip>
std::wstring Time::DisplayGameTime()
{
std::wstringstream message;
message
<< L"Current Time: "
// D,M,Y,H using default format ...
<< L" " << Days()
<< L", " << Months()
<< L", " << Years()
<< L" " << Hours()
// Add Minute using zero-padded, fixed width of 2 ...
<< L" : " << std::setw(2) << std::setfill(L'0') << Minutes();
return message.str();
}

正如您所发现的,to_wstring不允许您提供格式化选项。如果你想继续使用to_wstring,你必须自己应用格式。有很多选择,所以我会随机选择一个:

  • 始终准备"0"
  • 然后返回最右边的2位数字

类似这样的东西:

auto const minutesText = []() {
// Always prepend a "0"
auto const minute { L"0" + std::to_wstring(Minutes()) };
// Return the right-most 2 digits
return minute.substr(minute.length() - 2);
}();

如果你能使用C++20,事情会容易得多,通常很多也会更快。C++20引入了一个格式化库,它将简洁的格式化描述语言(类似于Python(与C++I/O流的类型安全性相结合。

它使以下实现成为可能:

#include <format>
std::wstring Time::DisplayGameTime()
{
return std::format(L"Current Time:  {}, {}, {} {} : {:02}",
Days(), Months(), Years(),
Hours(), Minutes());
}

std::formatprintf函数族类似,采用格式化字符串,外加零个或多个要插值的参数。格式化字符串描述了最终输出,以及参数的放置位置和格式。

前四个占位符不包含任何格式规范,并且产生类似于to_wstring的结果。最后的占位符{:02}对字段宽度(2(和填充字符(0(进行编码,以便在输出没有产生足够的字符时使用。它可以拼写为{:0>2}来指定右对齐的文本,但这是默认的整数值,所以我省略了它

使用C++20格式化库需要一个C++20编译器(实现它(。Visual Studio 2019和Visual Studio 2022都需要。两者都需要设置/std:c++-latest编译器选项。此时,C++20格式化库不会出现在/std:c++20编译器选项下。C++语言标准也可以从IDE中进行设置。


奖励材料:为什么std::format会这样做?-Charlie Barto-CppCon 2021:看看微软的实现,它解释了为什么std::format比I/O流快几个数量级。这不是介绍性材料。

相关内容

  • 没有找到相关文章

最新更新