getline(),直到输入结束

getline() until end of input C++

本文关键字:输入 结束 getline      更新时间:2023-10-16

这是我的代码。它应该在输入结束之前获取输入,并将该输入放入字符串data中。然后,它应该使用分隔符"#"对输入进行标记。然后,我反复调用函数nexttoken()来将标记存储在变量中。

std::istream_iterator<char> it(std::cin);
std::istream_iterator<char> end;
std::string data(it,end);
std::string delimiter = "#";
StringTokenizer strtok(data,delimiter);
std::string t1      = strtok.nextToken();
std::string t2      = strtok.nextToken();
当我像这样在命令行传递一个文件时,这一切都有效:
program.exe <testcase1.txt

testcase1.txt

S A B #
S -> a A #
S -> z B #
A -> b B c B #
B -> d A #
##

输出
S A B 
a: 1
b: 1
c: 1
d: 1
z: 1

everything check out and works.

我的问题是这样的:当我在IDE中推运行时,我可以手动输入输入,但当我这样做时,没有办法使程序接受输入,除非我按ctrl-z。这个问题在linux中也存在,当我在终端中传递文件时,它只是挂在那里让我输入无限行。

这里是我的代码的一个较小的版本,只计算3个标记,只检查a,b和c

main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <cstddef>
#include "StringTokenizer.h"
int countSubstring(const std::string& str, const std::string& sub)
{
    if (sub.length() == 0) return 0;
    int count = 0;
    for (size_t offset = str.find(sub); offset != std::string::npos;
     offset = str.find(sub, offset + sub.length()))
    {
        ++count;
    }
    return count;
}
int main(int argc, char* argv[1])
{
int task;
if (argc < 2)
{
    std::cout << "Error: missing argumentn";
    return 1;
}
task = atoi(argv[1]);
switch(task){
    case 0:
        {
std::istream_iterator<char> it(std::cin);
std::istream_iterator<char> end;
std::string data(it,end);
std::string delimiter = "#";
StringTokenizer strtok(data,delimiter);
   int a = 0;
   int b = 0;
   int c = 0;
//reading the first token and puting it in tk1
std::string t1      = strtok.nextToken();
std::string tk1(t1);
tk1.erase(0, tk1.find_first_not_of(" "));
tk1.erase(tk1.find_last_not_of(" ")+1);
// token 2 and 3 are different because 1 is always the same format
std::string t2      = strtok.nextToken();
std::string tk2(t2);
            if(countSubstring(tk2,"a") > 0)
    {
        a = a + 1;
    }
            if(countSubstring(tk2,"b") > 0)
    {
         b=b  + 1;
    }
            if(countSubstring(tk2,"c") > 0)
    {
         c=c  + 1;
    }
std::string t3      = strtok.nextToken();
std::string tk3(t3);
if(countSubstring(tk3,"a") > 0)
    {
        a = a + 1;
    }
            if(countSubstring(tk3,"b") > 0)
    {
         b=b  + 1;
    }
            if(countSubstring(tk3,"c") > 0)
    {
         c=c  + 1;
    }
// this is where the output is
std::cout << tk1 << std::endl;

    if(a > 0)
  {
      std::cout << "a: " << a <<std::endl;
  }
    if(b > 0)
  {
      std::cout << "b: " << b <<std::endl;
  }
    if(c > 0)
  {
      std::cout << "c: " << c <<std::endl;
  }
          }
  break;
  //////////////////////////////////////////////////
    case 1:
        break;
    case 2:
        break;
    default:
        std::cout << "Error: unrecognized task number " << task << "n";
        break;
}
return 0;
}

StringTokenizer.h

#ifndef INCLUDE_STRINGTOKENIZER_H
#define INCLUDE_STRINGTOKENIZER_H

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>

class StringTokenizer
{
public:
   StringTokenizer(const std::string& _str, const std::string& _delim);
  ~StringTokenizer(){};

   std::string nextToken();
   std::string nextToken(const std::string& delim);

private:
   std::string  token_str;
   std::string  delim;
};
#endif

StringTokenizer.cpp

#include "StringTokenizer.h"
StringTokenizer::StringTokenizer(const std::string& _str, const std::string& _delim)
{
   if ((_str.length() == 0) || (_delim.length() == 0)) return;
   token_str = _str;
   delim     = _delim;
   /*
     Remove sequential delimiter
   */
   unsigned int curr_pos = 0;
   while(true)
   {
      if ((curr_pos = token_str.find(delim,curr_pos)) != std::string::npos)
      {
         curr_pos += delim.length();
         while(token_str.find(delim,curr_pos) == curr_pos)
         {
            token_str.erase(curr_pos,delim.length());
         }
      }
      else
       break;
   }
   /*
     Trim leading delimiter
   */
   if (token_str.find(delim,0) == 0)
   {
      token_str.erase(0,delim.length());
   }
   /*
     Trim ending delimiter
   */
   curr_pos = 0;
   if ((curr_pos = token_str.rfind(delim)) != std::string::npos)
   {
      if (curr_pos != (token_str.length() - delim.length())) return;
      token_str.erase(token_str.length() - delim.length(),delim.length());
   }
}


std::string StringTokenizer::nextToken()
{
   if (token_str.length() == 0)
     return "";
   std::string  tmp_str = "";
   unsigned int pos     = token_str.find(delim,0);
   if (pos != std::string::npos)
   {
      tmp_str   = token_str.substr(0,pos);
      token_str = token_str.substr(pos+delim.length(),token_str.length()-pos);
   }
   else
   {
      tmp_str   = token_str.substr(0,token_str.length());
      token_str = "";
   }
   return tmp_str;
}

std::string StringTokenizer::nextToken(const std::string& delimiter)
{
   if (token_str.length() == 0)
     return "";
   std::string  tmp_str = "";
   unsigned int pos     = token_str.find(delimiter,0);
   if (pos != std::string::npos)
   {
      tmp_str   = token_str.substr(0,pos);
      token_str = token_str.substr(pos + delimiter.length(),token_str.length() - pos);
   }
   else
   {
      tmp_str   = token_str.substr(0,token_str.length());
      token_str = "";
   }
   return tmp_str;
}

1:我如何改变我的代码,使它将停止搜索输入当我完成输入?或者当它看到##已经输入时?(##表示输入结束)

2:这在我当前的代码中是可能的吗?

Linux和我的IDE都用g++编译

您正在使用来自std::cid的输入流来读取数据,它只会在到达文件结束时停止,这就是为什么您需要终止输入,在windows中使用Ctrl-z,在Linux中使用Ctrl-d

最简单的变化是逐行读取并独立处理它们。这将允许您读取终止标记##而不继续进行(假设标记实际上是两个#后面跟着一个新行)。

std::string line;
while (std::getline(std::cin, line)) {
   if (line == "##") break;
   // process a single line
}

如果不能保证分隔符后面跟着一行,则可能需要逐个字符地读取,但这是不可能的。