【问题标题】:How to read-and-validate from istringstream by fields如何按字段从 istringstream 读取和验证
【发布时间】:2013-03-11 17:30:05
【问题描述】:

我正在尝试检查输入的有效性。我得到一个文件,其中有两列,第一列是字符串,第二列是整数。分隔符是任意数量的空格。问题是,我无法弄清楚如何正确检查第二项是否真的是 int。考虑这段代码:

string line; // parameter with a string to be parsed
string name;
int num;
istringstream lineStream(line);
lineStream >> name;
lineStream >> num;

通过调用lineStream.good(),我可以检测到诸如“abcd g”之类的输入,但是当我输入“abcd 12a”之类的内容时,它会被解析为“abcd”和12。与“abcd 12.2”等相同。

在 Java 中,我可以将 String.split() 用于数组,然后解析每个整个元素,而不忽略任何字符,但我不知道这里的正确方法是什么。

感谢提示

【问题讨论】:

  • 假设您的拆分是基于空格到字符串中,您可以在 C++ 中实现相同的“拆分”策略,然后验证各个实体,但最终问题是公平的。您似乎在问如何验证被提取的 element 实际上是完整和简洁的,也许是如何通过流属性收集该信息。好问题。我会对解决此问题的不同方法感兴趣。
  • 我想知道是否有办法简单地做到这一点,即使用流。创建一个 char* 数组可能会很麻烦,然后对它们进行标记并检查有效性,这是真的。

标签: c++ parsing istream


【解决方案1】:

在提取int 后,您可以简单地检查是否到达std::stringstream 行的末尾。如果int 提取失败,则根本没有整数。如果成功但流中仍有内容,则说明行中内容过多。我会这样处理这个问题:

std::string line, name;
int num;
while (std::getline(file, line)) {
  std::stringstream line_stream(line);
  if (line_stream >> name >> num &&
      line_stream.eof()) {
    // Line was of the correct format
  }
}

基本上有两种检查:

  1. 如果无法提取stringintline_stream >> name >> num 将失败。
  2. 在这些提取之后,如果它们到达流的末尾,将设置eof 位。因此,如果流中仍有内容,line_stream.eof() 将失败。

显然,这是一种非常脆弱的方法,仅适用于特定情况,并且几乎需要适应行格式的任何变化。

【讨论】:

  • @JerryCoffin 那是一个common misconception(几乎就像认为!eof() 是一个好的while 条件一样普遍)。 eof 在提取结束时设置 - 在阅读之前使用它不是一个好的条件。
  • 如果第二个字段后面有空格,这将不起作用,是吗?
  • @MartinMelka 确实不会。它只允许专门<somestring> <whitespace> <int>。你想在最后允许空格吗?
  • 我想是的。也许如果我最后打电话给line_stream >> somestring,它会消耗空格并因此移动到eof? (然后我可以检查somestring.length()==0 是否可以消除流中其他内容的可能性)?
  • @MartinMelka 这听起来很合理。
【解决方案2】:

你可以读取两个字符串,然后检查第二个字符串是否真的是一个数字。像这样的:

std::string line; // parameter with a string to be parsed
std::string name;
std::string strNum;
int num;
std::istringstream lineStream(line);
lineStream >> name;
lineStream >> strNum;

if (isNumber(strNum))
{
   num = atoi(strNum.c_str());
}

//

bool isNumber(const std::string& strNum)
{
   bool lIsNumber = true;
   std::string::const_iterator it = strNum.begin();
   while (it != strNum.end())
   {
      if (!std::isdigit(*it))
      {
         lIsNumber = false;
         break;
      }
      ++it;
  }
   return lIsNumber;
}

【讨论】:

  • 我想应该可以。它不会考虑其余的线路,但这很容易做到。为什么我没有想到这一点? :O
猜你喜欢
  • 2021-02-28
  • 1970-01-01
  • 2021-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-15
  • 1970-01-01
相关资源
最近更新 更多