I want to know if there is a lambda or a clean short format in order to find if a single string contains only numeric values e.g 0 - 9 and the full stop character e.g . only. For example string "123.45" should pass and strings "12jd", "12.4f" etc should fail.
CodePudding user response:
This would be the code for your check, the constexpr stuff makes the function evaluatable at compile time. And the static_assert checks the output at compile time. Basically doing a unit test at compile time.
string_view is a nice wrapper for string literals and makes the string literal more easy to pass into the function and allows the use of a range based for loop to loop over all the characters.
#include <cassert>
#include <string_view>
constexpr bool is_positive_number(const std::string_view number_string)
{
std::size_t number_of_points{ 0ul };
// loop over all characters in string
for (const auto character : number_string)
{
// a '.' is valid but there should only be one
if (character == '.')
{
number_of_points ;
if (number_of_points > 1) return false;
}
else
{
// if character is not a '.' then it must be betweern '0'-'9'
if ((character < '0') || (character > '9')) return false;
}
}
return true;
}
int main()
{
static_assert(is_positive_number("1"));
static_assert(is_positive_number("12"));
static_assert(is_positive_number("123"));
static_assert(is_positive_number("1."));
static_assert(is_positive_number("1.2"));
static_assert(is_positive_number("12.34"));
static_assert(is_positive_number("007"));
static_assert(!is_positive_number("12.3.4"));
static_assert(!is_positive_number("-123"));
static_assert(!is_positive_number("abc"));
//auto lambda = [](const char* number_string)
auto lambda = [](const std::string& number_string)
{
return is_positive_number(number_string);
};
auto is_ok = lambda("123");
assert(is_ok);
return 0;
}
CodePudding user response:
This can be done with a straightforward scan of the text:
bool is_valid(const std::string& str) {
int dots = 0;
for (char c: str) {
if (c == '.')
dots;
if (1 < dots || !std::isdigit(c))
return false;
}
return true;
}
CodePudding user response:
Using std::regex produces a two-liner if you dont count the static pattern
#include <string>
#include <regex>
#include <cassert>
bool is_positive_number( const std::string& str ) {
static std::regex rx("^(\\ ?)(0|([1-9][0-9]*))(\\.[0-9]*)?$"); // Getting the regex object
std::smatch match;
return std::regex_match(str,match,rx);
}
int main()
{
assert(is_positive_number("1"));
assert(is_positive_number("12"));
assert(is_positive_number("123"));
assert(is_positive_number("1."));
assert(is_positive_number("1.2"));
assert(is_positive_number("12.34"));
assert(is_positive_number(" 12.34"));
assert(!is_positive_number("007"));
assert(!is_positive_number("123.23.23"));
assert(!is_positive_number("-123"));
assert(!is_positive_number("abc"));
return 0;
}
CodePudding user response:
Another way would be to use the open-source compile-time regex library:
#include <ctre.hpp>
constexpr bool is_positive_number(std::string_view const s) noexcept {
return static_cast<bool>(ctre::match<R"(\d (?:\.\d )?)">(s));
}
int main() {
static_assert(is_positive_number("1.2"));
static_assert(!is_positive_number("1..2"));
static_assert(!is_positive_number("1e2"));
}
CodePudding user response:
This does not check all the cases like repeated dots but it's a one-liner
bool ok = str.find_first_not_of( "0123456789." )==std::string::npos;
Use as in
#include <algorithm>
#include <string>
constexpr bool is_positive_number( const std::string_view& str ) {
return str.find_first_not_of( "0123456789." )==std::string::npos;
}
int main()
{
static_assert(is_positive_number("1"));
static_assert(is_positive_number("12"));
static_assert(is_positive_number("123"));
static_assert(is_positive_number("1."));
static_assert(is_positive_number("1.2"));
static_assert(is_positive_number("12.34"));
static_assert(is_positive_number("007"));
static_assert(!is_positive_number("-123"));
static_assert(!is_positive_number("abc"));
return 0;
}
CodePudding user response:
I don't think there is a built-in function that does exactly what you were looking for. There is std::stod
that converts a string
into a double
and tells you how many characters were converted successfully. However, there are many non-conforming numbers that will work, such as -1
, NAN
, 10E 3
.
One way you could do is first remove all numbers(0~9), then check against ""
and "."
:
constexpr bool is_num(std::string str)
{
std::erase_if(str, [](unsigned char c){ return std::isdigit(c);};
return str == "" || str == ".";
}
Note erase_if
is from C 20, for pre-C 20, you would do:
constexpr bool is_num(std::string str)
{
str.erase(std::remove_if(str.begin(), str.end(),
[](unsigned char c){ return std::isdigit(c); }), str.end());
return str == "" || str == ".";
}