The following regex-based function supports both signed integer literals and decimal literals in standard and scientific notation (e.g. 42, 3.14, -1, +58., 4e2, 1.e-2, -12.34e-56, .1E4). Integers prefixed with zeros are also matched (e.g. 0001):
#include <string_view>
#include <regex>
bool is_number(std::string_view s) {
static std::regex const re{
R"([-+]?((\.\d+)|(\d+\.)|(\d+))\d*([eE][-+]?\d+)?)"};
return std::regex_match(s.data(), re);
}
Hexadecimal literals, binary literals, single-quote separators and suffixes (f, F, l, L, u, U, ll, LL, Z) are not matched.
Below are some unit tests using gtest. The complete code is available at https://godbolt.org/z/vbTnMx7or
TEST(IsNumber, True) {
char const *tests[]{"42", "3.14", "-0", "+4", ".3",
"+.5", "-.23", "7.", "1e2", "1.e2",
"1.0e-2", "8.e+09", "2E34", "61e2", "-0e1",
"+0E+10", "-.01E-5", "07", "+01E1", "12.34"};
for (auto const &x : tests) {
EXPECT_TRUE(is_number(x));
}
}
TEST(IsNumber, False) {
char const *tests[]{"4e", "xyz", ".3.14", "--0", "2-4",
"..3", ".+5", "7 2", "1f", "1.0f",
"1e-2.0", "8e+0e1", "2E.4", "a", "e15",
"-0e10.3", ".e2", "+1.2E0e", "1.2+3", "e1"};
for (auto const &x : tests) {
EXPECT_FALSE(is_number(x));
}
}