Что лучший способ состоит в том, чтобы сделать контроль ввода в C++ с cin?

Следующие работы для меня:

sysuse auto, clear
collapse (sum) price mpg, by(make)
estpost tabstat price mpg, by(make)
matrix A = e(price)', e(mpg)'
esttab matrix(A), title("Summary statistics: mean") nomtitle

Summary statistics: mean
--------------------------------------
                    price          mpg
--------------------------------------
1                    4099           22
2                    4749           17
3                    3799           22
4                    9690           17
5                    6295           23
6                    9735           25
7                    4816           20
8                    7827           15
9                    5788           18
10                   4453           26
11                   5189           20
12                  10372           16
13                   4082           19
14                  11385           14
15                  14500           14
16                  15906           21
17                   3299           29
18                   5705           16
19                   4504           22
20                   5104           22
21                   3667           24
22                   3955           19
23                   6229           23
24                   4589           35
25                   5079           24
26                   8129           21
27                   3984           30
28                   4010           18
29                   5886           16
30                   6342           17
31                   4296           21
32                   4389           28
33                   4187           21
34                   5799           25
35                   4499           28
36                  11497           12
37                  13594           12
38                  13466           14
39                   3995           30
40                   3829           22
41                   5379           14
42                   6165           15
43                   4516           18
44                   6303           14
45                   3291           20
46                   8814           21
47                   5172           19
48                   4733           19
49                   4890           18
50                   4181           19
51                   4195           24
52                  10371           16
53                  12990           14
54                   4647           28
55                   4425           34
56                   4482           25
57                   6486           26
58                   4060           18
59                   5798           18
60                   4934           18
61                   5222           19
62                   4723           19
63                   4424           19
64                   4172           24
65                   3895           26
66                   3798           35
67                   5899           18
68                   3748           31
69                   5719           18
70                   7140           23
71                   5397           41
72                   4697           25
73                   6850           25
74                  11995           17
Total            6165.257      21.2973
--------------------------------------
8
задан 14 revs, 5 users 100% 15 October 2009 в 02:36
поделиться

8 ответов

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

42crap

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

Так или иначе вот то, как можно отклонить number-non-number вышеупомянутых. Считайте строку в строку, затем проанализируйте ее с a stringstream:

std::string getline() {
  std::string str;
  std::getline(std::cin, str);
  return str;
}

int choice;
std::istringstream iss(getline());
iss >> choice >> std::ws;
if(iss.fail() || !iss.eof()) {
  // handle failure
}

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

Используются более ранние версии этого ответа std::cin непосредственно - но std::ws не будет работать хорошо вместе с std::cin подключенный к терминалу (это заблокирует вместо этого ожидание пользователя для ввода чего-то), таким образом, мы будем использовать a stringstream для чтения целого числа.


Ответ на некоторые вопросы:

Вопрос: 1. Используя попытку ловят блок. Это не работало. Я думаю, что это вызвано тем, что исключение не повышено из-за плохого входного.

Ответ: Ну, можно сказать потоку выдавать исключения при чтении чего-то. Вы используете istream::exceptions функция, которую Вы говорите, для которого вида ошибки Вы хотите бросить исключение:

iss.exceptions(ios_base::failbit);

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

Вопрос: 2. Я попробовал if(!cin){ //Do Something } который не работал также. Я еще не понял этого.

Ответ: Это могло прибыть из того, что Вы дали ему что-то как "42crap". Для потока, который является абсолютно допустимым входом при выполнении извлечения в целое число.

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

Ответ: atoi Стандартный Совместимый. Но не хорошо, когда Вы хотите проверить ошибки. Нет никакой проверки ошибок, сделанной им в противоположность другим функциям. Если Вы имеете строку и хотите проверить, содержит ли она число, то сделайте это как в первоначальном коде выше.

Существуют подобные C функции, которые могут читать непосредственно из струны до. Они существуют для разрешения взаимодействия со старым, унаследованным кодом и написанием быстрого кода выполнения. Нужно избежать их в программах, потому что они работают довольно низкий уровень и требуют сырых данных использования явные указатели. По самой своей природе они не могут быть улучшены для работы с определяемыми пользователем типами также. А именно, это говорит о функции "strtol" (строка-к-длинному), которая является в основном atoi с проверкой ошибок и возможностью работать с другими основаниями (шестнадцатеричное число, например).

Вопрос: 4. Если я пишу класс, который использует cin, но динамично этот вид обнаружения ошибок, возможно, путем определения типа входной переменной во времени выполнения, он будет иметь слишком много служебным? Это даже возможно?

Ответ: Обычно Вы не должны заботиться слишком много об издержках здесь (если Вы имеете в виду издержки во время выполнения). Но это зависит конкретно от того, где Вы используете тот класс. Тот вопрос будет очень важен, если Вы запишете высокопроизводительную систему, которая обрабатывает вход и должна иметь высоко повсюду. Но если необходимо считать вход из терминала или файла, Вы уже видите то, к чему это сводится: Ожидание пользователя для ввода чего-то действительно занимает много времени, Вы не должны наблюдать затраты во время выполнения в этой точке больше в этом масштабе.

Если Вы имеете в виду код наверху - хорошо он зависит от того, как код реализован. Необходимо было бы просканировать строку, которую Вы читаете - содержит ли она число или нет, ли некоторая произвольная строка. В зависимости от того, что Вы хотите просканировать (возможно, Вам вводили "дату" или формат ввода "времени" также. Изучить boost.date_time для этого), Ваш код может стать произвольно сложным. Для простых вещей как классификация между числом или нет, я думаю, что можно сойти с рук небольшой объем кода.

17
ответ дан 3 November 2019 в 12:28
поделиться
  • Для получения исключений с iostreams, необходимо установить надлежащий флаг исключения для потока.
  • И я использовал бы get_line для получения, целая строка входа и затем обработать его соответственно - используют lexical_cast, регулярные выражения (например, Повышение Regex или Повышение Xpressive, анализируют его с Духом Повышения или просто используют некоторую соответствующую логику
4
ответ дан 3 November 2019 в 12:28
поделиться

Забудьте об использовании отформатированного входа (>> оператор) непосредственно в реальном коде. Необходимо будет всегда читать необработанный текст со станд.:: getline или подобный и затем используют Ваши собственные входные стандартные программы парсинга (который может использовать>> оператор) проанализировать вход.

2
ответ дан 3 November 2019 в 12:28
поделиться

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

Затем мне нравится использовать повышение:: бросок lexical_, который может повысить bad_ lexical_ исключение броска, если вход не может быть преобразован.

В Вашем примере:

std::string in_str;
cin >> in_str;

// optionally, test if it conforms to a regular expression, in case the input is complex

// Convert to int? this will throw bad_lexical_cast if cannot be converted.
int my_int = boost::lexical_cast<int>(in_str);
3
ответ дан 3 November 2019 в 12:28
поделиться

Это - то, что я делаю с C, но это, вероятно, применимо для C++ также.

Введите все как строку.

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

12
ответ дан 3 November 2019 в 12:28
поделиться

Как насчет комбинации различных подходов:

  1. Поймайте вход от std::cin использование std::getline(std::cin, strObj) где strObj a std::string объект.

  2. Использовать boost::lexical_cast выполнить лексический перевод из strObj или к целому числу со знаком или к целому числу без знака самой большой ширины (например, unsigned long long или что-то подобное)

  3. Использовать boost::numeric_cast разрушать целое число к ожидаемому диапазону.

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

2
ответ дан 3 November 2019 в 12:28
поделиться

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

1
ответ дан 3 November 2019 в 12:28
поделиться

Одна вещь, которая не была упомянута еще, состоит в том, что обычно важно, чтобы Вы протестировали, чтобы видеть, работала ли cin>> операция перед использованием переменной, которая, предположительно, получила что-то от потока.

Этот пример подобен Вашему, но делает тот тест.

#include <iostream>
#include <limits>
using namespace std;
int main()
{
   while (true)
   {
      cout << "Enter a number: " << flush;
      int n;
      if (cin >> n)
      {
         // do something with n
         cout << "Got " << n << endl;
      }
      else
      {
         cout << "Error! Ignoring..." << endl;
         cin.clear();
         cin.ignore(numeric_limits<streamsize>::max(), '\n');
      }
   }
   return 0;
}

Это будет использовать обычный оператор>> семантика; это пропустит пробел сначала, затем попытаться считать столько цифр, сколько это может и затем останавливаться. Так "42crap" даст Вам, 42 затем перескакивают через "дерьмо". Если это не то, что Вы хотите, то я соглашаюсь с предыдущими ответами, необходимо считать его в строку и затем проверить его (возможно, использование регулярного выражения - но это может быть излишеством для простой числовой последовательности).

1
ответ дан 3 November 2019 в 12:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: