在整数输入中跳过单个减号或加号

时间:2013-03-16 19:01:44

标签: c++ validation

最近我需要一个简单的程序来对标准输入上出现的所有整数求和,每行一个整数。输入碰巧包含一些未设置的行,包含一个减号(' - ')符号,还有一些带有垃圾字符的行(要忽略)。

我相信,这将是一个微不足道的计划。但事实证明,单个减号不会表现为其他糟糕的输入。在正常的非整数输入上,设置了失败标志,坏输入保留在输入缓冲区中。但是使用单个减号(或加号)设置失败标志,但+/-符号被删除,导致程序跳过下一个(有效)整数(导致错误的总和)。

我写了一个小测试程序(下面)来分析行为。 上述行为+/-是一个错误还是一个特征?

#include <iostream>

using namespace std;

int main()
{
  string s;
  int n;

  while (true)
  {
    n = -4711;
    cin >> n;

    cerr << (cin.bad()  ? "ERROR: badbit is set\n" : "");
    cerr << (cin.fail() ? "ERROR: failbit is set\n" : "");
    cerr << (cin.eof()  ? "ERROR: eofbit is set\n" : "");

    if ( cin.bad() || cin.eof() )
      break;

    if ( cin.fail() )
    {
      cin.clear();
      cin >> s;
      cerr << "ERROR: ignored string '" << s
           << "' (integer is '" << n << "')" << endl;
    }
    else
    {
      cout << "OK: read integer '" << n << "'" << endl;
    }
  }
  return 0;
}

运行程序(输入:“1 asdf 2 - 3 + 4 qwer 5”):

~ $ ./a.out
1 asdf 2 - 3 + 4 qwer 5 
OK: read integer '1'
ERROR: failbit is set
ERROR: ignored string 'asdf' (integer is '0')
OK: read integer '2'
ERROR: failbit is set
ERROR: ignored string '3' (integer is '0')
ERROR: failbit is set
ERROR: ignored string '4' (integer is '0')
ERROR: failbit is set
ERROR: ignored string 'qwer' (integer is '0')
OK: read integer '5'

(我已经通过读取字符串解决了我原来的问题,并使用带有异常的C ++ 11 stoi来识别错误的输入。)

编辑:如果有人对我原来问题的解决方案感兴趣:

#include <iostream>
#include <string>

using namespace std;

int main()
{
  int sum = 0;
  string n;

  while ( cin >> n )
  {
    try {
      sum += stoi(n);
      cout << n << endl;
    }
    catch (exception& e)
    {
      cerr << e.what() << " ERROR: '" << n << "' is not a number." << endl;
    }
  }
  cout << sum << endl;

  return 0;
}

2 个答案:

答案 0 :(得分:2)

这是一个功能。 cin直到它读取' - '之后的空格才知道输入是错误的。没有可移植的方式使用iostreams来放回多个单个字符,并且没有可移植的方式来查找cin。所以它被卡住了,不得不把' - '留下来。

在阅读数据时,有一点是对自己的解析更好。将所有数据读入字符串,然后自己解析这些字符串以确定什么是真实的以及什么是垃圾。这样你就可以完全控制而不是与iostream所做的任何事情作斗争。

答案 1 :(得分:1)

我会这样做:

#include <locale>
#include <sstream>
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>

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

    static mask const *get_table() { 
        static std::vector<mask> rc(table_size, space);

        std::fill_n(&rc['0'], 10, digit);
        return &rc[0]; 
    } 
};

int main() { 
    std::string input("1 asdf 2 - 3 + 4 qwer 5 ");
    std::istringstream x(input);

    // use our ctype facet:
    x.imbue(std::locale(std::locale(), new number_only));

    // initialize vector from the numbers in the file:
    std::vector<int> numbers((std::istream_iterator<int>(x)), 
                                std::istream_iterator<int>());

    // display what we read:
    std::copy(numbers.begin(), numbers.end(), 
        std::ostream_iterator<int>(std::cout, "\n"));

    return 0;
}