问题描述
我正在尝试将 wstring_view
转换为 int
。是否有类似 stoi
的东西适用于 wstring_view
而不是 string
?不能使用任何 C-api,因为它不一定以 null 结尾。不能使用 from_chars
,因为它是 wchar_t
。到目前为止,我一直在转换为 std::wstring
,然后转换为 int
(使用 stoi
),这对于小字符串优化等可能没问题,但与使用的点背道而驰首先是视图。
解决方法
这是我发现有效的方法:
#include <cwchar>
#include <optional>
#include <string_view>
std::optional<int> StrToInt(std::wstring_view const view) noexcept {
wchar_t format_str[13]; // % + 10digits + d + \0 = 13 characters
std::swprintf(format_str,std::size(format_str),L"%%%dd",(int)view.size());
int res;
if (std::swscanf(view.data(),format_str,&res) != 1) return std::nullopt;
return res;
}
由于我们在 format_str
中明确指定了大小,因此视图不需要以 null 结尾。
如果我们已经验证字符串只包含数字字符(没有符号字符,没有前导或尾随空格等)并且不会溢出,我们可以使用更简单的未经检查的例程:
int UncheckedStrToInt(std::wstring_view const str) noexcept {
int res = 0;
for (auto ch : str)
res = res * 10 + (ch - '0');
return res;
}
我做了一些benchmarks。 swscanf
的性能比 stoi
差很多。我将使用 stoi
或 UncheckedStrToInt
,具体取决于 wstring_view
是否已验证。
std::stoi(std::wstring)
只是 std::wcstol()
的包装器,您可以直接调用它。但是,它需要一个以 null 结尾的 wchar_t*
字符串,但正如您所指出的,std::wstring_view
不能保证以 null 结尾。
由于 32 位 int
最多有 10 个十进制数字,加上一个可选符号,加上空终止符,您可以简单地将 std::wstring_view
数据复制到本地 wchar_t[12]
数组中,以空字符结尾,然后用 std::wcstol()
、std::swscanf()
等进行转换。
或者,您可以创建从 FILE*
数据读取的自定义 std::wstring_view
流,例如通过 fmemopen()
或等效方式,然后您可以使用 std::fwscanf()
。
或者,您可以编写一个(或找到第 3 方)自定义 std::basic_streambuf
派生类来读取 std::wstring_view
,然后您可以将该类的实例提供给标准 {{ 1}} 对象并使用其 std::istream
提取 operator>>
。