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

标签 c++ linux

这是我的代码。它应该在输入结束之前获取输入并将该输入放入字符串 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

测试用例1.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

检查一切正常。

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

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

主要.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 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;
}

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
}

如果不能保证分隔符后跟单行,您可能需要逐个字符地阅读,但这种情况不太可能发生。

关于c++ - getline() 直到输入 C++ 结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39908913/

相关文章:

c++ - 使用 C++ 和 QWT 移动图形

C++数组问题

linux - 增加屏幕尺寸,移动虚拟屏幕

linux - 如何通过filezilla客户端下载文件?

linux - 配置文件发现意外的 $end,不知道为什么

c++ - 在 C++ 中存储结果 int*long 的最佳数据类型是什么

c++ - Qt QException 子类抛出,但 QUnhandledException 被捕获

c++ - 以 fstream::out 模式打开 fstream 是否会删除其当前内容?

Java 1.6 -> 1.7 JNLP = SIGSEGV

java - 使用 jmap 查找当前堆大小