从 StringStream 中提取字符的 noskipws 导致它不适用于后续字符串提取

noskipws on char extraction from StringStream causes it to not work with subsequent string extractions

提问人:Ashkan Arabi 提问时间:8/8/2023 最后编辑:DailyLearnerAshkan Arabi 更新时间:9/5/2023 访问量:51

问:

让我简单一点。为什么下面的程序写“Thi”而不是“Thisisatest”?我希望它在第一个循环中写入前两个字符,然后写入测试字符串的其余部分,不带空格。

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

int main() {
  string test = "This is just a test.";
  stringstream ss(test);
  
  char c;
  int i = 0;
  while (ss >> noskipws >> c) { 
    int ascii = (int)c;
    if (i > 2) { // break after writing 2 characters
      break;
    }
    i++;
    cout << c; 
  }

  // continue using the same sstring, 
  // but with a string instead of a char
  // notice that there is no noskipws here
  string s;
  while(ss >> s) {
    cout << s; 
  }

  // program exits with only "Thi" printed
  return 0;
}

有趣的是,删除可以解决问题。为什么呢?>> noskipws

C++ 爱马尼普

评论

1赞 Igor Tandetnik 8/8/2023
第一个循环将流留在 之后的空间上,并设置了 still。然后,不读取任何字符,根据文档,这会导致它在流上设置 ,这反过来又会导致循环退出。Thisnoskipwsss >> sfailbitwhile
0赞 Ashkan Arabi 8/8/2023
@IgorTandetnik 谢谢!我以为每次都必须重新应用。我通过简单地添加到第二个循环来获得预期的行为。noskipwsskipws

答:

0赞 273K 8/8/2023 #1

简化的代码(第一个循环读取 4 个字符并在打印第 4 个字符之前退出):

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

int main() {
  string test = " is just a test.";
  stringstream ss(test);
  ss >> noskipws;
  
  string s;
  while(ss >> s) {
    cout << s; 
  }
  cout << ss.fail();
}
// Output: 1.

提取到字符串有一个合约

提取并追加字符,直到出现以下任一情况:

  • 文件结束发生在输入序列上;
  • isspace(c, is.getloc())对于下一个可用的输入字符 为 true。c

如果未提取任何字符,则在流上设置。std::ios::failbit

ss >> s然后,对于上面的每一次阅读,工作都是如此。 在第一个字符上为 true - 未提取任何内容,为空,流设置为失败状态。str.erase()str.append(1, c)cisspace(c, is.getloc())sss

1赞 tbxfreeware 8/8/2023 #2

ss >> s表示在字符串 S 中读取,并在遇到空格时停止。

我在您的程序中添加了一对额外的输出语句,每个循环的末尾一个。第一个循环结束后,输入流被定位为输入空格作为其下一个字符。

当程序尝试输入字符串 s 时,它会立即遇到空格,并且由于您将流配置为不跳过前导空格,因此它会停止,无法输入字符串 s。该故障会导致流进入失败状态。

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

int main() {
    string test = "This is just a test.";
    stringstream ss(test);

    char c;
    int i = 0;
    while (ss >> noskipws >> c) {
        int ascii = (int)c;
        if (i > 2) { // break after writing 2 characters
            break;
        }
        i++;
        cout << c;
    }
    std::cout << boolalpha 
        << "\nAfter first loop: " 
        << "\n  ss.fail() : " << ss.fail() 
        << "\n  c         : \'" << c << '\''
        << "\n";

    // continue using the same sstring, 
    // but with a string instead of a char
    // notice that there is no noskipws here
    string s{ "value before ss >> s" };
    while (ss >> s) {
        cout << s;
    }
    std::cout << "\nAfter second loop: "
        << "\n  ss.fail() : " << ss.fail()
        << "\n  s         : \"" << s << '\"'
        << '\n';

    // program exits with only "Thi" printed
    return 0;
}

输出如下:

Thi
After first loop:
  ss.fail() : false
  c         : 's'

After second loop:
  ss.fail() : true
  s         : ""