1

我有一个包含整数和特殊含义字符“#”的输入流。它看起来如下: ... 12 18 16 # 22 24 26 15 # 17 # 32 35 33 ... 标记用空格分隔。'#' 的位置没有模式。

我试图像这样标记输入流:

int value;
std::ifstream input("data");
if (input.good()) {
  string line;
  while(getline(data, line) != EOF) {
    if (!line.empty()) {
      sstream ss(line);
      while (ss >> value) {
        //process value ...

      }
    }
  }
}

此代码的问题是遇到第一个“#”时处理停止。

我能想到的唯一解决方案是将每个单独的标记提取成一个字符串(不是'#')并使用 atoi() 函数将字符串转换为整数。但是,由于大多数令牌是整数,因此效率非常低。在令牌上调用 atoi() 会带来很大的开销。

有没有办法可以按类型解析单个令牌?即,对于整数,将其解析为整数,而对于'#',跳过它。谢谢!

4

6 回答 6

2

一种可能性是显式跳过空格 ( ss >> std::ws),然后使用ss.peek()它来确定 a 是否#跟随。如果是,则用于ss.get()读取并继续,否则用于ss >> value读取值。

如果 的位置#无关紧要,您也可以'#'在用它初始化之前从行中删除所有stringstream内容。

于 2012-10-06T19:06:51.483 回答
2

通常不值得对 good() 进行测试

if (input.good()) {

除非您的下一个操作是生成错误消息或异常。如果它不好,那么所有进一步的操作都会失败。

不要针对EOF.

而(getline(数据,行)!= EOF){

std::getline() 的结果不是整数。它是对输入流的引用。输入流可转换为可在 bool 上下文中使用的类似 bool 的对象(如while if等)。所以你想要做什么:

while(getline(data, line)) {

我不确定我会读一行。您可以只阅读一个单词(因为输入是空格分隔的)。对字符串使用 >> 运算符

std::string word;
while(data >> word) {  // reads one space separated word

现在你可以测试这个词,看看它是否是你的特殊字符:

if (word[0] == "#")

如果不将单词转换为数字。

这就是我要做的:

// define a class that will read either value from a stream
class MyValue
{
  public:
    bool isSpec() const {return isSpecial;}
    int  value()  const {return intValue;}

    friend std::istream& operator>>(std::istream& stream, MyValue& data)
    {
        std::string item;
        stream >> item;
        if (item[0] == '#') {
            data.isSpecial = true;
        } else
        {   data.isSpecial = false;
            data.intValue  = atoi(&item[0]);
        }
        return stream;
    }
  private:
    bool isSpecial;
    int  intValue;
};

// Now your loop becomes:
MyValue  val;
while(file >> val)
{
    if (val.isSpec())  { /* Special processing */ }
    else               { /* We have an integer */ }
}
于 2012-10-06T21:07:32.013 回答
1

也许您可以将所有值读取为 std::string 然后检查它是否为“#”(如果不是 - 转换为 int)

于 2012-10-06T19:09:27.490 回答
1
int value;
std::ifstream input("data");
if (input.good()) {
    string line;
    std::sstream ss(std::stringstream::in | std::stringstream::out);
    std::sstream ss2(std::stringstream::in | std::stringstream::out);
    while(getline(data, line, '#') {
        ss << line;
        while(getline(ss, line, ' ') {
            ss2 << line;
            ss2 >> value
            //process values ...
            ss2.str("");  
        }
        ss.str("");
    }
}

在这里,我们首先在第一个 while 循环中用标记 '#' 分割行,然后在第二个 while 循环中,我们用 ' ' 分割行。

于 2012-10-06T19:50:08.197 回答
0

就个人而言,如果您的分隔符始终是空格,无论后面是什么,我建议您只需将输入作为字符串并从那里解析。这样,您可以获取字符串,查看它是数字还是 # 等等。

于 2012-10-06T19:08:46.977 回答
0

我认为您应该重新检查您的前提,即“在令牌上调用 atoi() 会带来很大的开销-”

没有什么神奇的std::cin >> val。在引擎盖下,它最终调用(非常类似于)atoi。

如果您的令牌很大,则创建 a 可能会产生一些开销,std::string但正如您所说,绝大多数是数字(其余是#),因此它们应该很短。

于 2012-10-06T19:10:19.600 回答