仅当它包含任何换行符时,如何才能从 stringstream 中读取一行?
How can I read a line from a stringstream only if it contains any newline?
我正在将一些网络数据作为 input_buffer.
读入字符串流
数据是由 LF 字符分隔的 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;
}
这应该打印 "test123" 和 "OK",而不是 "partial line"。
如前所述 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:
我认为 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;
}
它按预期打印前两行,"partial line" 留在向量中。
或者更好的是,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;
}
我正在将一些网络数据作为 input_buffer.
读入字符串流数据是由 LF 字符分隔的 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;
}
这应该打印 "test123" 和 "OK",而不是 "partial line"。
如前所述 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:
我认为 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;
}
它按预期打印前两行,"partial line" 留在向量中。
或者更好的是,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;
}