Step 5 of 7
Strict number parsing with from_chars
Parsing numbers from untrusted input (files, network messages, user typing) is where many programs go wrong. The older tools each have a problem:
std::stoithrows exceptions, and silently ignores trailing junk:stoi("12abc")is 12.atoican't report errors at all:atoi("abc")is 0, just likeatoi("0").
std::from_chars from <charconv> has none of these problems: no exceptions, no locale, no allocation, and precise error reporting. It's also the fastest parser in the standard library.
#include <charconv>
#include <iostream>
#include <string_view>
void check(std::string_view s) {
int v = 0;
auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), v);
std::cout << "'" << s << "': ";
if (ec == std::errc::invalid_argument) std::cout << "no number\n";
else if (ec == std::errc::result_out_of_range) std::cout << "too big for int\n";
else if (ptr != s.data() + s.size()) std::cout << v << " but junk after it: '" << ptr << "'\n";
else std::cout << "ok " << v << "\n";
}
int main() {
check("123");
check("-45");
check("12abc");
check("abc");
check("99999999999");
check(" 7");
}
'123': ok 123
'-45': ok -45
'12abc': 12 but junk after it: 'abc'
'abc': no number
'99999999999': too big for int
' 7': no number
How it works
from_chars(first, last, value)parses from the character range[first, last). For astring_view, that'ss.data()tos.data() + s.size().- It returns a struct with
ptr(where parsing stopped) andec(an error code, or a defaultstd::errc()on success). Structured bindings unpack both. - If
ptrdidn't reach the end, there were extra characters after the number. - It accepts a leading
-, but not a leading+or spaces, which is exactly the strictness you want for validating input.
(Printing ptr works in this example only because the string literals end in '\0'. A general string_view isn't guaranteed to.)
Your turn: write std::optional<int> to_int(std::string_view s) that accepts only a complete, in-range integer (optional leading -, no spaces, no junk).