Разбор целого числа со специализированными литералами в C++ без регулярного выражения
Я создал функцию, которая принимает аргумент
std::string_view
и возвращается
bool
квалифицируется ли данная строка как целое число или нет.
- Я включил унарные операторы
-
а также+
по каким-то причинам. - я использовал
starts_with
метод проверки префикса. - я использовал
contains
изC++23
или жеC++2b
чтобы проверить, содержит ли указанный набор символов такую вещь.
Мой
is_integer
исходный код функции:
bool is_number(const std::string_view& input_string) {
enum class number_flag {
DECIMAL, BINARY, OCTAL, HEX
};
auto it = input_string.begin();
std::string new_input_string;
bool result = true;
number_flag iflag;
/// check and foremost if it's empty 0
if (input_string.empty()) {
return false;
}
/// With unary positive and negative operators 1
if (input_string.starts_with('-') || input_string.starts_with('+')) {
++it;
new_input_string = input_string.substr(1, input_string.size() - 1);
} else {
new_input_string = input_string;
}
/// Classifying Different Formats (I)
/// decimal - starts with `1-9` non-zero digits next with digits `0-9`
/// binary - starts with `0b` or `0B` next with only `0` and `1`
/// octal - starts with `0` zero digit next with limited digits `0-7`
/// hex - starts with `0x` or `0X` next with digits `0-9` and limited alphabets `a-f` or `A-F`
/// starts-with (prefix) procedure 2
if (!new_input_string.starts_with('0')) {
// decimals
iflag = number_flag::DECIMAL;
++it;
} else if (new_input_string.starts_with("0b") || new_input_string.starts_with("0B")) {
// binary
iflag = number_flag::BINARY;
it += 2;
} else if (new_input_string.starts_with('0')) {
// octal
iflag = number_flag::OCTAL;
++it;
} else if (new_input_string.starts_with("0x") || new_input_string.starts_with("0X")) {
// hexadecimal
iflag = number_flag::HEX;
it += 2;
} else {
return false;
}
/// Classifying Different Formats (II)
/// decimal - starts with `1-9` non-zero digits next with digits `0-9`
/// binary - starts with `0b` or `0B` next with only `0` and `1`
/// octal - starts with `0` zero digit next with limited digits `0-7`
/// hex - starts with `0x` or `0X` next with digits `0-9` and limited alphabets `a-f` or `A-F`
using std::literals::operator""sv;
/// during-body procedure 3
for (; it != input_string.end(); ++it) {
switch (iflag) {
using enum number_flag;
case DECIMAL: {
if ("0123456789"sv.contains(*it)) {
result = true;
break;
} else
return false;
}
case BINARY: {
if ("01"sv.contains(*it)) {
result = true;
break;
} else
return false;
}
case OCTAL: {
if ("01234567"sv.contains(*it)) {
result = true;
break;
} else
return false;
}
case HEX: {
if ("0123456789abcdefABCDEF"sv.contains(*it)) {
result = true;
break;
} else
return false;
}
default: {
return false;
}
}
}
/// to do:
/// (1) Digit Separator `'`
/// (2) Suffixes `z`, `u`, `l`, ...
/// final procedure 4
return result;
}
Тесты:
1192837 -> true
+23123213 -> true
-1928739382 -> true
0b101011 -> true
0B1010101 -> true
0b18100100 -> false
071325612 -> true
01238791 -> false
0x032 -> false (unexpected)
0xff0ca8 -> false (unexpected)
<any single character excluding plus and minus> -> true (unexpected)
<any single character excluding plus and minus and next with digits> -> true (unexpected)
Как я могу решить эту проблему с такими неожиданными результатами? Что-то не так в моем коде (очень возможно)?
1 ответ
Поскольку вы указали «C++23» в качестве стандарта, это означает, что C++17 находится на рассмотрении. Итак, вот лучший способ написать свою функцию с помощью
from_chars
:
bool is_number(std::string_view input_string)
{
//Assumes no leading or trailing spaces.
//from_chars can't handle leading '+' characters.
if(input_string.starts_with('+')
input_string.remove_prefix(1);
auto *end_char = input_string.data() + input_string.size();
signed long long value;
auto [ptr, err] = std::from_chars(input_string.data(), end_char, &value, 0);
//Return false if it ends with non-valid numeric characters.
if(err == std::errc() && ptr == end_char)
return true;
else
return false;
}