convert wstring_view to int

876 Views Asked by At

I am trying to convert wstring_view to int. Is there something like stoi that works on wstring_view instead of string? Can't use any C-api's since it's not necessarily null-terminated. Can't use from_chars since it's wchar_t. So far, I've been converting to std::wstring, then converting to int (using stoi), which is probably OK with small string optimizations and all, but goes against the point of using views in the first place.

2

There are 2 best solutions below

0
On

Here's what I found that works:

#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;
}

Since we specify the size explicitly in format_str, view doesn't need to be null-terminated.

If we have verified that the string only contains numeric characters (no sign character, no leading or trailing spaces, etc.) and it won't overflow, we can use a simpler unchecked routine:

int UncheckedStrToInt(std::wstring_view const str) noexcept {
  int res = 0;
  for (auto ch : str)
    res = res * 10 + (ch - '0');
  return res;
}

I did some benchmarks. The swscanf performs much worse than stoi. I will be using stoi or UncheckedStrToInt depending on if the wstring_view is already verified.

enter image description here

6
On

std::stoi(std::wstring) is just a wrapper for std::wcstol(), which you can call directly. However, it requires a null-terminated wchar_t* string, but std::wstring_view is not guaranteed to be null-terminated, as you noted.

Since a 32bit int has a maximum of 10 decimal digits, plus an optional sign, plus the null-terminator, you could simply copy the std::wstring_view data into a local wchar_t[12] array, null-terminate it, and then convert that with std::wcstol(), std::swscanf(), etc.

Alternatively, you can create a custom FILE* stream that reads from the std::wstring_view data, such as via fmemopen() or equivalent, and then you can use std::fwscanf().

Alternatively, you can write a (or find a 3rd party) custom std::basic_streambuf-derived class that reads from the std::wstring_view, and then you can give an instance of that class to a standard std::istream object and use its operator>> to extract the int.