解析逗号分隔的数字(C++)

Parsing comma-delimited numbers in C++

本文关键字:数字 C++ 分隔      更新时间:2023-10-16

我有一个简短的问题要问大家。我正在尝试编写一个简单的代码来从用户输入中提取数字并将它们保存到 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;
}

在程序中,首先删除输入字符串中的"不需要的"逗号,然后遇到无法再区分输入行中的数字的问题。因此,似乎这些逗号毕竟不是不需要的。解决方案是逐步解析字符串,而无需先删除逗号,因为您需要它们来拆分输入字符串。下面是一个示例。

#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;
}

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

顺便说一句,你的问题非常实用,以至于它更适合标准的stackexchange站点 - 与计算机科学的联系非常弱。

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

在您的情况下,您有三个令牌: 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;
}

可以使用 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;
}

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

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

// set up some variables
vector<int> numbers(0);

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);
cout << "My numbers are: " << nums_in << endl;
string s_tmp = "";
int i_tmp;
for(vector<int>::size_type i = 0, len = nums_in.size(); i < len; i++){
    if( nums_in[i] == ',' ){
        if(s_tmp.size() > 0){
            i_tmp = std::stoi(s_tmp);
            numbers.push_back(i_tmp);
        }
        s_tmp = "";
    }
    else if( i == len-1){
        s_tmp += nums_in[i];
        i_tmp = std::stoi(s_tmp);
        numbers.push_back(i_tmp);
        cout << "My parsed numbers are:" << i_tmp << endl;
    }
    else {
        s_tmp += nums_in[i];
    }
}
cout << endl << endl;
cout << "Done." << endl;
return 0;
}