istringstream忽略第一个字母

3

我正在尝试使用std::istringstream访问字符串中的不同单词,并且我还在使用多个测试用例进行操作。

int t;
cin>>t;
while(t--)
{
     string arr;
     cin.ignore();
     getline(cin,arr);
     istringstream iss(arr);
     string word;
     while(iss>>word)
     {
          cout<<word;
      }
 }

对于第一个测试用例,一切都很完美(即输出正确的单词)。但是对于每个后续的测试用例,第一个单词的第一个字母会被留下来。
例如:
输入: 4 hey there hey hi hi hi my name is xyz girl eats banana
我得到的输出为:
输出: hey there hey i hi hi y name is xyz irl eats banana
请问有人能提供建议如何解决问题,以及为什么会出现这个错误?

请提供一个 [MCVE]。arr 实际上是什么? - πάντα ῥεῖ
是的,我做了,非常感谢您指出。 - amora
cin.ignore() 移至循环之前。同时尝试弄清它实际的作用。 - n. m.
3个回答

4
你的问题在于格式化输入,例如in >> value通常会在尝试读取之前跳过前导空格。另一方面,未格式化的输入不会跳过前导空格。在你的循环中使用 std::cin.ignore();,你假设 std::getline(std::cin, arr) 会像 t 的输入一样保留换行符。但事实并非如此。 std::getline() 提取并存储所有字符直到第一个停止的换行符,仍然提取换行符。所以,你需要从循环中删除 cin.ignore();
关键问题是如何在格式化输入和未格式化输入之间切换。由于在输入数字值时换行符可能以任意空格开头,而你可能也想忽略它们,因此有两种方法:
1. std::cin >> std::ws; 跳过所有前导空格。这可能包括行首的多个换行符和空格。跳过这些可能不一定是理想的。
2. std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 忽略所有字符,直到包括第一个换行符在内。这将允许紧随其后的空行以及以前导空格开头的行。

2

这一行是罪魁祸首:cin.ignore();

当没有任何参数调用std::basic_istream::ignore时,它忽略恰好1个字符。

在您的情况下,std::cin.ignore()将忽略第一个字母,但不是对于第一个测试用例,因为此时std::cin为空,因此没有内容可以被忽略。但是,std::cin包含其他单词,因此它会从第一个单词中忽略1个字符。


我认为在第一种情况下有些东西需要忽略,即换行符,但是下一次用户输入到达getline语句时,已经跳过了一个字符。 - Biruk Abebe

2
根据std::basic_istream::ignore文档:

从输入流中提取并丢弃字符,直到包括定界符为止。ignore的行为类似于UnformattedInputFunction

值得一提的是,如果流中没有要忽略的内容,std::basic_istream::ignore阻塞等待用户输入

基于这个,让我们分解一下您的代码:

  1. 在循环中第一次调用此函数时,它将忽略仍然存在于缓冲区中的换行符,该换行符来自前一个cin>>t操作。然后getline语句将等待并从用户读取一行。
  2. 接下来,由于缓冲区中没有要忽略的内容(因为std::getline不在缓冲区中保留换行符),它将阻塞等待输入以进行忽略。因此,下一次程序阻塞并等待输入是因为ignore()函数而不是您希望的getline函数,并且当你提供输入时(即你的第二个测试用例),输入的一个字符将被忽略。
  3. 下一个getline函数不会阻塞,因为在上一个ignore函数之后留下了缓冲区中的内容,所以getline将读取剩余的字符串,这将恰好少一个字符。
  4. 该过程从第2步继续,直到循环终止。
int t;
cin>>t;//this leaves new line character in the buffer
while(t--)
{
    string arr;
    cin.ignore();//this will ignore one character from the buffer,so the first time 
                //it will ignore the new line character from the previous cin input
               //but next time it will block and wait for input to ignore
    getline(cin,arr);//this will not block if there is something in the buffer 
                    //to read
     ...
}

解决方案是将ignore语句移出循环并放在cin>>t语句旁边。在这种情况下最好使用ignore(INT_MAX,'\n');。您可能还想阅读此答案,了解何时以及如何使用ignore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接