用C ++解析逗号分隔的数字

时间:2016-02-28 13:58:58

标签: c++ parsing

我对每个人都有一个简单的问题。我正在尝试编写一个简单的代码来从用户输入中提取数字并将它们保存到一个int数组中,但是我很难想到如何让它工作。下面显示的代码适用于单位数字,但对于数字超过1位的数字则不然。

例如,如果用户输入:1,2,3,4,50,60,这就是我得到的:

Enter numbers (must be comma delimited): 1,2,3,4,50,60
My numbers are: 12345060
My parsed numbers are: 1
My parsed numbers are: 2
My parsed numbers are: 3
My parsed numbers are: 4
My parsed numbers are: 5
My parsed numbers are: 0

问题:如何修改这段简单的代码以准确捕获超过1位的数字?在此先感谢!!

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
using namespace std;


// set up some variables
int numbers[100];


int main() {

// Enter numbers (comma delimited). Ex: 1,2,3,4,50,60<return>
cout << endl << endl << "Enter numbers (must be comma delimited): ";

string nums_in;
getline(cin, nums_in);
nums_in.erase(remove(nums_in.begin(), nums_in.end(), ','), nums_in.end());  // remove the unwanted commas

cout << "My numbers are: " << nums_in << endl;


// convert each char into int
for (int o = 0; o < 6; o++) {
    istringstream buf(nums_in.substr(o,1));
    buf >> numbers[o];
    cout << "My parsed numbers are: " << numbers[o] << endl;
}
cout << endl << endl;

cout << "Done." << endl;
return 0;

}

4 个答案:

答案 0 :(得分:1)

要解决此类问题,您必须编写扫描程序。扫描仪将输入分为令牌。一旦你能够将输入分解为标记,就可以检查标记的顺序(参见解析器)。

在您的情况下,您有三个令牌:numbercommaend。有效输入的示例:number comma number end。另一个例子:end(空输入)。无效输入的示例:number number end(数字之间没有逗号)。

下面是您的问题的可能解决方案。 get_token从输入中读取令牌并将其存储在tokennumber全局变量中。 get_numbers读取令牌,检查语法并将数字存储在numbers中;数字的计数存储在count(也是全局变量)中。

#include <iostream>
#include <cctype>

enum { max_count = 100 };
int numbers[max_count];
int count;

enum token_type
{
  token_unknwon,
  token_end,
  token_comma,
  token_number
};

token_type token;
int number;

token_type get_token()
{
  char c;

  // get a character, but skip ws except newline
  while ( std::cin.get( c ) && c != '\n' && std::isspace( c ) )
    ;
  if ( ! std::cin || c == '\n' )
    return token = token_end;

  if ( c == ',' )
    return token = token_comma;

  if ( std::isdigit( c ) )
  {
    std::cin.unget();
    std::cin >> number;
    return token = token_number;
  }

  return token_unknwon;
}

enum error_type
{
  error_ok,
  error_number_expected,
  error_too_many_numbers,
  error_comma_expected
};

int get_numbers()
{
  // 
  if ( get_token() == token_end )
    return error_ok; // empty input

  while ( true )
  {
    // number expected
    if ( token != token_number )
      return error_number_expected;

    // store the number
    if ( count >= max_count )
      return error_too_many_numbers;
    numbers[count++] = number;

    // this might be the last number
    if ( get_token() == token_end )
      return error_ok;

    // not the last number, comma expected
    if ( token != token_comma )
      return error_comma_expected;

    // prepare next token
    get_token();
  }

}

int main()
{
  //...
  switch ( get_numbers() )
  {
  case error_ok: break;
  case error_comma_expected: std::cout << "comma expected"; return -1;
  case error_number_expected: std::cout << "number expected"; return -2;
  case error_too_many_numbers: std::cout << "too many numbers"; return -3;
  }

  //
  std::cout << count << " number(s): ";
  for ( int i = 0; i < count; ++i )
    std::cout << numbers[i] << ' ';
  //...
  return 0;
}

答案 1 :(得分:1)

使用std::getline可以轻松完成此任务,以读取字符串中的整行,然后使用std::istringstream解析该字符串,以提取单个数字并跳过逗号。

#include <iostream>
#include <sstream>
#include <vector>

using std::cout;

int main() {   
    // Enter numbers (comma delimited). Ex: 1,2,3,4,50,60<return>
    cout << "\nEnter numbers (must be comma delimited): ";

    int x;
    std::vector<int> v;
    std::string str_in;

    // read the whole line then use a stringstream buffer to extract the numbers
    std::getline(std::cin, str_in);
    std::istringstream str_buf{str_in};

    while ( str_buf >> x ) {
        v.push_back(x);
        // If the next char in input is a comma, extract it. std::ws discards whitespace
        if ( ( str_buf >> std::ws).peek() == ',' ) 
            str_buf.ignore();
    }

    cout << "\nMy parsed numbers are:\n";
    for ( int i : v ) {
        cout << i << '\n';
    }

    cout << "\nDone.\n";

    return 0;

}

答案 2 :(得分:0)

在你的程序中,首先删除输入字符串中的“不需要的”逗号,然后遇到无法区分输入行中的数字的问题。所以似乎这些逗号毕竟不是不受欢迎的。解决方案是逐步解析字符串而不首先删除逗号,因为您需要它们来拆分输入字符串。这是一个例子。

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>

int main() {

    // Enter numbers (comma delimited). Ex: 1,2,3,4,50,60<return>
    std::cout << std::endl << std::endl << "Enter numbers (must be comma delimited): ";
    std::string nums_in;
    std::getline(std::cin, nums_in);

    // Now parse
    std::vector<int> data;
    std::istringstream buf(nums_in);
    while (!buf.eof()) {
        int this_number;
        buf >> this_number;
        if (buf.bad()) {
            std::cerr << "Number formatting error!\n";
            return 1;
        }
        data.push_back(this_number);
        char comma = 0;
        buf >> comma;
        if (!buf.eof()) {
            if (buf.fail()) {
                std::cerr << "Could not read comma.\n";
                return 1;
            }
            if (comma!=',') {
                std::cerr << "Found no comma but '" << comma << "' instead !\n";
                return 1;
            }
        }
    }

    std::cout << "My numbers are:";
    for (auto a : data) {
        std::cout << " " << a;
    }
    std::cout << std::endl;

    std::cout << "Done." << std::endl;
    return 0;
}

请注意,我没有使用“using namespace std;”因为它被认为是不好的风格。此外,我使用C ++ 11功能打印出值并使用向量来存储数字 - 在您的代码中,键入包含200个数字的行会导致崩溃(或其他不良行为)。最后,解析错误处理尚未完成。使其完整和正确是一项练习。基于istringstream的方法的替代方法是首先用逗号分割行,然后使用istringstreams分别读取所有数字。

顺便说一下,你的问题是如此实用,以至于它更适合标准的stackexchange网站 - 与计算机 science 的连接非常薄弱。

答案 3 :(得分:0)

嗯...如何在不删除逗号的情况下解析字符串?读取字符的字符串字符,将每个字符放在临时缓冲区中,直到您点击逗号,然后将临时缓冲区转换为int并将其存储在向量中。清空临时缓冲区并重复。

componentWillReceiveProps