getline()直到输入C ++结束

时间:2016-10-07 03:30:39

标签: c++ linux

这是我的代码。它应该在输入结束之前输入并将输入放入字符串数据。然后它应该使用分隔符“”来标记输入。然后我反复调用我的函数nexttoken()将标记存储在变量中。

program.exe <testcase1.txt

当我在命令行上传递文件时,这一切都有效:

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

testcase1.txt

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

输出

#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 argument\n";
    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;
}

一切都结束并有效。

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

这是我的代码的较小版本,只计算3个令牌,只检查a,b和c

的main.cpp

#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.h

#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;
}

StringTokenizer.cpp

df1 = pd.DataFrame({'A': ['1', '2', '3', '4','5'],
                  'B': ['1', '1', '1', '1','1'],
                  'C': ['A', 'A1', 'A2', 'A3','A4'],
                  'D': ['B0', 'B1', 'B2', 'B3','B4'],
                  'E': ['A', 'A', 'S', 'S','S']})
df2 = pd.DataFrame({'A': ['1', '6', '9', '4'],
                  'C': ['c', 'c1', 'c2', 'c3'],
                  'D': ['d1', 'd1', 'd2', 'd3']})

1:如何更改代码,以便在完成输入后停止搜索输入?或者什么时候可以看到##已被输入? (##标志着输入结束)

2:这是否可以使用我当前的代码?

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

1 个答案:

答案 0 :(得分:1)

您正在使用来自std::cid的输入流来读取数据,这些数据只会在您到达文件结尾时停止,这就是您需要终止输入的原因Windows中的 Ctrl-z 和Linux中的 Ctrl-d

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

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

如果无法保证分隔符后跟一行,则可能需要逐个字符地读取,但这不太可能。