如果只包含任何换行符,我如何从字符串流中读取一行?

时间:2017-01-07 13:50:17

标签: c++ string buffer line

我将一些网络数据作为input_buffer读入字符串流。

数据是由LF char分隔的ASCII行。

input_buffer可能处于其中只有部分行的状态。

我试图调用getline (),但只有在实际上字符串流中的新换行符时才会调用。换句话说,它应该提取已完成的行,但在缓冲区中留下部分行。

这是一个MVCE:

#include <string>
#include <sstream>
#include <iostream>

int
main (void)
{
  std::stringstream input_buffer;
  input_buffer << "test123\nOK\n";
  while (input_buffer.str ().find ('\n') != std::string::npos)
    {
      std::string line;
      std::getline (input_buffer, line, '\n');
      std::cout << "input_buffer.str ().size: " << input_buffer.str ().size () << "\n";
      std::cout << "line: " << line << "\n";
    }
  return 0;
}

它目前没有终止,这是输出的一个片段:

input_buffer.str ().size: 11
line: test123
input_buffer.str ().size: 11
line: OK
input_buffer.str ().size: 11
line: 
input_buffer.str ().size: 11
...

如果只包含任何换行符,我怎样才能读取字符串流中的一行?

编辑:为了澄清这里是另一个部分输入的代码示例:

#include <string>
#include <sstream>
#include <iostream>
#include <vector>

void
extract_complete_lines_1 (std::stringstream &input_buffer, std::vector<std::string> &lines)
{
  while (input_buffer.str ().find ('\n') != std::string::npos)
    {
      std::string line;
      std::getline (input_buffer, line, '\n');
      lines.push_back (line);
    }
}

void
print_lines (const std::vector<std::string> &v)
{
  for (auto l : v)
    {
      std::cout << l << '\n';
    }
}

int
main (void)
{
  std::vector<std::string> lines;
  std::stringstream input_buffer {"test123\nOK\npartial line"};
  extract_complete_lines_1 (input_buffer, lines);
  print_lines (lines);
  return 0;
}

这应打印&#34; test123&#34;和&#34;好的&#34;,但不是&#34;部分行&#34;。

2 个答案:

答案 0 :(得分:0)

如上所述here,您可以覆盖缓冲区的underflow函数,以便使用您可以指定的函数重新填充。

以下是改编自here的示例:

#include <iostream>
#include <sstream>
#include <string>

class Mybuf : public std::streambuf {
    std::string line{};
    char ch{}; // single-byte buffer
protected:
    int underflow() override {
        if(line.empty()) {
            std::cout << "Please enter a line of text for the stream: ";
            getline(std::cin, line);
            line.push_back('\n');
        }
        ch = line[0];
        line.erase(0, 1);
        setg(&ch, &ch, &ch + 1); // make one read position available
        return ch; 
    }
public:
    Mybuf(std::string line) : line{line} {};
};

class mystream : public std::istringstream {
    Mybuf mybuf;

public:
    mystream(std::string line) : std::istringstream{}, mybuf{line}
    {
        static_cast<std::istream&>(*this).rdbuf(&mybuf);
    }
};

int main()
{
    mystream ms{"The first line.\nThe second line.\nA partial line"};
    for(std::string line{}; std::getline(ms, line); )
        std::cout << "line: " << line << "\n";
}

输出:

line: The first line.
line: The second line.
Please enter a line of text for the stream: Here is more!
line: A partial lineHere is more!
Please enter a line of text for the stream:

答案 1 :(得分:0)

我认为使用std::stringstream并不容易。我尝试使用tellg ()seekg ()来操纵流位置,但它们的行为并不像我预期的那样。

我找到了一个使用std::vector<char>作为缓冲区的解决方案:

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

void
extract_complete_lines (std::vector<char> &buf, std::vector<std::string> &lines)
{
  auto pos = std::end (buf);
  while ((pos = std::find (std::begin (buf), std::end (buf), '\n')) != std::end (buf))
    {
      std::string line (std::begin (buf), pos);
      buf.erase (std::begin(buf), pos + 1);
      lines.push_back (line);
    }
}

void
print_lines (const std::vector<std::string> &v)
{
  for (auto l : v)
    {
      std::cout << l << '\n';
    }
}

int
main (void)
{
  std::vector<std::string> lines;
  const std::string test_input = "test123\nOK\npartial line";
  std::vector<char> input_buffer {std::begin (test_input), std::end (test_input)};
  extract_complete_lines_1 (input_buffer, lines);
  print_lines (lines);
  return 0;
}

按预期打印前两行,&#34;部分行&#34;留在向量中。

或者甚至更好,std::vector<char>std::string

没有什么不同
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

void
extract_complete_lines (std::string &buf, std::vector<std::string> &lines)
{
  std::string::size_type pos;
  while ((pos = buf.find ('\n')) != std::string::npos)
    {
      lines.push_back (buf.substr (0, pos));
      buf.erase (0, pos + 1);
    }
}

void
print_lines (const std::vector<std::string> &v)
{
  for (auto l : v)
    {
      std::cout << l << '\n';
    }
}

int
main (void)
{
  std::vector<std::string> lines;
  std::string input_buffer = "test123\nOK\npartial line";
  extract_complete_lines (input_buffer, lines);
  print_lines (lines);
  return 0;
}