Есть ли в C функция для выбора чисел внутри строки

#c #string #c 11 #integer

#c #строка #c 11 #целое число

Вопрос:

У меня есть калькулятор из стеков на c , и когда я пытаюсь вставить в него формулу, например 1 2*3 Я хотел бы, чтобы у меня была функция, которая получала бы числа до тех пор, пока каждый символ не станет числом. Пример 12 2 он получит 12, затем пропустит , потому что код попадет в другой раздел, а затем снова получит число 2. Я сделал что-то вроде

 for(i=0;i  ;i<string.size();)

 {
    if(string[i]<48)
    character(string[i]);
    else if (string[i]>=48)
    number(string[i]);
 }
 

Но это неэффективно, кто-то знает для этого функцию?

Комментарии:

1. std::stringstream предназначено для этого.

Ответ №1:

Существует не совсем одна функция, которая делает то, что вы хотите, но для нее все еще больше поддержки, чем большинство людей понимают. Когда вы считываете число из потока, оно знает, что нужно пропускать пробелы перед цифрами, поэтому, даже если поток содержит что-то вроде » 1234″, вы можете просто прочитать целое число и получить 1234 .

Поток, в свою очередь, использует языковой стандарт, чтобы указать, что является или не является пробелом, и поэтому его следует игнорировать, пока он пытается прочитать число. Локаль, в свою очередь, в основном представляет собой просто набор фасетов. Фасет, который используется для классификации того, является ли символ пробелом или нет, является ctype фасетом.

Итак, чтобы получить то, что мы хотим, нам нужен ctype фасет, который классифицирует все символы на две категории: цифры и пробелы. Чтобы получить это, мы можем сделать что-то вроде этого:

 struct digits_only: std::ctype<char> {
    digits_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table() {
        // a table with one entry for each possible value of char.
        // we'll start with it classifying everything as whitespace:
        static std::vector<std::ctype_base::mask>
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        // now fill in the digits to say they're digits:
        std::fill_n(amp;rc['0'], 10, std::ctype_base::digit);
        return amp;rc[0];
    }
};
 

Итак, тогда нам нужно создать поток, указать потоку использовать языковой стандарт с этим аспектом (называемый «наполнением» потока), а затем мы можем читать наши данные, как если бы они содержали только числа:

 int main()
{
    std::string input("1 2*3/(44 55)");
    std::istringstream buf(input);
    buf.imbue(std::locale(std::locale(), new digits_only()));

    int value;
    while (buf >> value) // just read numbers from the stream
        std::cout << value << 'n';
}
 

[Я немного приукрасил строку (добавил несколько скобок и пару двузначных чисел).]

Результат довольно скучный, но показывает, о чем (я полагаю) вы просите:

 1
2
3
44
55
 

Комментарии:

1. Этот сайт действительно потрясающий, спасибо, это было именно то, что я искал.

Ответ №2:

если это будет работать только для целых чисел, вы можете использовать evergreen atoi() из stdlib вот документация https://www.cplusplus.com/reference/cstdlib/atoi / , есть также atof() и atol() , которые делают то же самое, но с двойным и длинным int

Ответ №3:

Прежде всего, вы foor loop совершенно неправы. В любом ресурсе C (например https://www.w3schools.com/cpp/cpp_for_loop.asp ) вы увидите, что существует только 3 утверждения:

 for (statement 1; statement 2; statement 3) {}
 

Оператор 1 выполняется (один раз) перед выполнением блока кода.

Оператор 2 определяет условие для выполнения блока кода.

Оператор 3 выполняется (каждый раз) после выполнения блока кода.

Во-вторых, почему бы не попробовать is_alpha() ? Я думаю, это ответит на ваш вопрос. Конечно, вам все равно нужно перебирать строку.

В-третьих, в Интернете есть множество примеров такого калькулятора. Просто посмотрите вокруг.

Комментарии:

1. извините, цикл for был неправильным, потому что у меня не было компьютера со мной, я просто закодировал его из своего разума и ошибся, ха-ха, is_alpha() у меня не работает, потому что он просто получает алфавит, а не символы ‘/, *, , -‘.

Ответ №4:

Вы имеете в виду, например std::stoi , но пропускаете все не цифры, а не только пробелы?

Обычное решение состоит в том, чтобы сначала преобразовать строку в подстроки, такие как {"1", " ", "2", "*", "3"} , а затем соответствующим образом преобразовать токены. Попытка впоследствии рекомбинировать ваши числа 1, 2, 3 с вашими операторами ,* кажется беспорядочной и подверженной ошибкам.


Кстати, использование магических чисел, как 48 в вашем коде, является плохим стилем по ряду причин:

  1. повторяющиеся магические числа в любом случае плохая идея, потому что их трудно читать и очень легко неправильно ввести только один из них как 49, и его трудно найти
  2. если вам действительно необходимо жестко запрограммировать код ASCII для 0 , рассмотрите 0x30 вместо 48 — шестнадцатеричные значения цифр гораздо более удобочитаемы, IMO
  3. но ASCII — это деталь платформы (хотя и довольно распространенная), поэтому лучше вообще не использовать жесткий код
  4. вам не нужно самостоятельно писать какую-либо классификацию символов, независимо от кодировки: просто используйте isdigit etc — вот для чего они существуют

Комментарии:

1. Да, isdigit() работает нормально, но он работает только в том случае, если в строке всего 1 число, если оно имеет значение 10 * 6, оно не получает 10, оно получает 1, затем 0, затем 6

2. Да, вам нужно запустить его в цикле или использовать find_if_not(begin, end, isdigit) или что-то в этом роде