Разбор целого числа со специализированными литералами в 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;
}
Другие вопросы по тегам