2017-01-07 28 views
1

我正在將一些網絡數據作爲input_buffer讀入一個stringstream。只有當它包含任何換行符時,我如何才能從stringstream讀取一行?

數據是由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」,而不是「分線」。

+1

它不會終止,因爲你重複地從字符串的開始搜索。從'input_buffer'中讀取不會改變底層內容。 – molbdnilo

+0

當你已經結束時,'input_buffer.eof()'將成立。 –

+0

[This](http://stackoverflow.com/q/12351163/1460794)可能是相關的。 – wally

回答

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

它打印按預期和「局部線」被留在載體中的頭兩行。


甚至更​​好,一個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; 
} 
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"; 
} 

輸出:

​​
+0

不幸的是,連接是長期居住的,我在回調中獲得了大量的數據,所以我不能依賴「正確的」istream。這就是我將數據添加到字符串流的原因。否則'getline()'根本不起作用。 – Promi

+0

好的。所以你從網絡功能創建一個'stringstream'。那麼你希望在閱讀每一行之後stringstream保持打開狀態,並且你不想讀一行直到'eof'的行,只能讀到換行符? – wally

+0

是的,串流保持打開狀態,直到連接關閉。它用作將部分數據重組爲整行的緩衝區。部分數據不應該從它讀取,直到它完成(但它不再是部分;))。它用作FIFO。 – Promi

相關問題