строковый ввод, как определить, является ли он int? - PullRequest
3 голосов
/ 02 декабря 2011

Я пишу программу, которая преобразует паратензивное выражение в математическое и оценивает его. У меня уже есть бит вычисления.

Я использую стек для операндов и очередь для чисел. Добавление операндов в стек не является проблемой, но мне нужно определить, является ли входной символ целым числом, и если это так, добавить его в очередь. Вот некоторый код:

cout << "Enter the numbers and operands for the expression";
string aString;

do
{
   cin >> aString
   if (aString = int) // function to convert to read if int, convert to int
   {
    c_str(...);
    atoi(...);
    istack.push(int);
   }
 }

Вот где я застрял. Я знаю, что мне придется использовать c_str и atoi, чтобы преобразовать его в int. Я выбрал неправильный подход?

Ответы [ 7 ]

6 голосов
/ 02 декабря 2011

Используйте метод .fail() потока.

Если вам также нужна строка, вы можете сначала прочитать строку, затем попытаться преобразовать строку в целое число, используя объект stringstream, и проверить .fail() в потоке строки, чтобы увидеть, можно ли выполнить преобразование.

cin >> aString;

std::stringstream ss;
ss << aString;
int n;
ss >> n;

if (!ss.fail()) {
  // int;
} else {
  // not int;
}
2 голосов
/ 02 декабря 2011

Вы можете либо запустить вашу функцию, которая преобразует строковое представление числа в двойное число, и посмотреть, есть ли ошибка, либо вы можете просмотреть содержимое строки и посмотреть, соответствует ли оно шаблону числа, а затем выполнить конверсия.

Вы можете использовать boost::lexical_cast<double>() или std::stod() (C ++ 11), где об ошибках сообщается с исключением, или экстракторы istringstream, где об ошибке сообщается путем установки бита сбоя, или с функциями преобразования C, которые сообщают об ошибках с помощью установка глобальной (скорее локальной) переменной errno.

try {
    istack.push_back(std::stod(aString));
} catch(std::invalid_argument &e) {
    // aString is not a number
}

или

errno = 0;
char const *s = aString.c_str();
char *end;
double result = strtod(s,&end);
if(EINVAL==errno) {
    // the string is not a number
} else {
    istack.push_back(result);
}

Реализация второй опции может использовать регулярное выражение, чтобы увидеть, соответствует ли строка шаблону, который вы используете для чисел, и если это так, то после запуска вашей функции преобразования. Вот пример шаблона, который вы можете ожидать для значений с плавающей запятой:

std::regex pattern("[+-]?(\d*.\d+|\d+.?)([eE][+-]?\d+)?");
if(std::regex_match(aString,pattern)) {
    istack.push_back(std::stod(aString));
} else {
    // aString is not a number
}

Кроме того, это, вероятно, не имеет значения для вас, но большинство любых встроенных методов для преобразования строки в число будут так или иначе чувствительны к локали. Один из способов изолировать себя от этого - использовать созданный вами струнный поток и наполнить его классическим языковым стандартом.

2 голосов
/ 02 декабря 2011

Вероятно, меня за это возмутят пуристы C ++.

Однако иногда библиотека C ++ - это просто больше работы, чем библиотека C.Я предлагаю это решение разработчикам на C.И разработчики C ++, которые не возражают против использования некоторых функций библиотеки C.

Вся проверка и преобразование могут быть выполнены в одной строке C с использованием функции sscanf.

   int intval;
   cin >> aString

   if (sscanf(aString.c_str(), "%d", &intval)){
       istack.push(intval);
   }

sscanf возвращает количество входных аргументов, которые были сопоставлены и назначены.Так что в этом случае он ищет одно стандартное значение типа int со знаком.Если sscanf возвращает 1, то ему удалось присвоить значение.Если он возвращает 0, то у нас нет int.

2 голосов
/ 02 декабря 2011

Если вы ожидаете целое число, я бы использовал boost::lexical_cast.

std::string some_string = "345";
int val = boost::lexical_cast<int>(some_string);

Если он не может привести к целому числу, он бросит. Производительность довольно разумна, и она сохраняет ваш код очень чистым.

Я не знаю ни о какой не бросающей версии. Вы можете использовать что-то вроде этого, хотя я обычно стараюсь не допустить, чтобы исключения управляли программой.

bool cast_nothrow(const std::string &str, int &val) {
  try {
    val = boost::lexical_cast<int>(str);
    return true;
  } catch (boost::bad_lexical_cast &) {
    return false;
  }
}

Edit:

Я бы не советовал проверять целочисленную проверку структуры, как вы описали. Хорошие функции делают одно и одно хорошо.

Обычно вам нужен более формальный синтаксический анализатор для обработки таких вещей. Мой честный совет - встроить язык сценариев или библиотеку в ваш проект. Это нетривиально, так что пусть кто-то другой делает тяжелую работу.

Если бы я действительно попытался реализовать то, что вы предлагаете, я бы, вероятно, сделал бы решение на основе стека, сохраняя уровни скобок в их собственном стековом фрейме. Самое простое - просто жестко закодировать простые операторы (скобки, сложения, подпрограммы и т. Д.) И предположить, что все остальное - число.

В конце концов вы захотите, чтобы все было разбито на какой-то тип выражения. Это может выглядеть примерно так:

struct Expression {
  virtual ~Expression() {}
  virtual float value() const = 0;
};

struct Number : public Expression {
  virtual float value() const {return val;}
  float val;
};

struct AdditionOper : public Expression {
  virtual float value() const {return lhs->value() + rhs->value();}
  boost::shared_ptr<Expression> lhs;
  boost::shared_ptr<Expression> rhs;
};

Я бы начал с разбора скобок, они будут определять порядок ваших выражений. Затем я разделил бы все на основе числовых операндов и начал бы помещать их в выражения. Тогда у вас останутся такие случаи, как 3 + 4 * 6, которые потребуют некоторой осторожности для правильного порядка операций.

Удачи.

1 голос
/ 02 декабря 2011

Я полагаю, что C ++ (без повышения) будет выглядеть так:

do
{
  std::stringstream ss;
  std::string test;
  cin >> test;
  ss << test;
  int num;
  if (ss >> num) // function to convert to read if int, convert to int
  {
    std::cout << "Number : " << num << "\n";
  }
}while(true); // don't do this though..
0 голосов
/ 04 декабря 2011

Особенно, если вы делаете ввод base-10, я считаю, что наиболее вопиющим шагом является чтение строки, а затем проверка того, что она содержит только допустимые символы:

string s;
cin >> s;
if(strrspn(s.c_str(), "0123456789")==s.length()){
    //int
} else{
    //not int
}
0 голосов
/ 02 декабря 2011

Вы не можете использовать ctype.h http://www.cplusplus.com/reference/clibrary/cctype/. Я использовал это раньше и не попал в беду.

...