从连续的字符串流中提取线

Extracting lines from continuous flow of strings

我想从连续的字符串数据流中提取行。但是数据格式不正确,我想丢弃提取的行,这样内存就不会越界。

比如我的串口输出是这样的:

第 1 批

POS 30 10 20\n
POS 30 10 21\n
POS 30 1

第 2 批

        0 22\n
POS 30 10 23\n
PO

有没有一种方法可以有效地保存数据并从中提取行?

这是我的代码:

stringstream ss;
while (SP->IsConnected())
{
    string result = SP->ReadData();
    ss << result;
    string oneline;
    while(getline(ss, oneline))
    {
        cout << oneline << endl;
        // or do something more interesting...
    }
}

但是我的代码不起作用,因为 getline() 修改了字符串流,因此无法向其插入更多数据,而且我想保持字符串流内存较小。所以我认为我不能使用 getline() 而是使用 'popline()' 之类的东西,如果它存在的话。

根据评论的提示,我想出了自己的不使用 stringstream 的 popline()。谢谢评论。

// like getline() for istream, but made for string and pops out the line from the input
bool popline(string& input, string& output, char delim = '\n')
{
    size_t i = 0;
    string line;
    for (char ch : input)
    {
        line.push_back(ch);
        ++i;
        if (ch == delim)
        {
            output = line;
            input.erase(0, i);  // erase the extracted line (unlike getline)
            return true;
        }
    }
    return false;   // return without producing the line string when end is reached (unlike getline)
}

所以我的主要功能变为

string st;
while (SP->IsConnected())
{
    string result = SP->ReadData();
    st += result;
    string oneline;
    while(popline(st, oneline))
    {
        cout << oneline << endl;
        // or do something more interesting...
    }
}

πìντα ῥεῖ 暗示了 OP 的第一个剪辑失败的原因。

while(getline(ss, oneline))

最终到达 ss 的末尾并设置 EOF 错误标志。一旦发生这种情况,在使用 clear.

确认错误标志之前,流将不会做任何事情。

它还会提取到流的末尾,抓取任何部分行并破坏 OP 在读取之间缓冲数据的尝试。

我在想 OP 可能想要更原始一点。我通常用 read 函数中的 char 数组做这样的事情。这是完全愚蠢和万无一失的。与 findsubstring 方法相比,这很可能在速度上损失了几分,但更容易正确。

stringstream ss;
while (SP->IsConnected())
{
    string result = SP->ReadData(); // get blob of unknown size and contents
    for (char ch: result) // read through blob character by character
    {
        if (ch != '\n') // not a delimiter, store
        {   
            ss << ch;
        }
        else // got a complete token. May have taken multiple ReadData calls
             // note that this also leaves the delimiter out of the data passed 
             // on to further parsing. Usually a good thing.
        {
            cout << ss.str()<< endl; // handle token
            ss.str(std::string()); 
            // depending on how you parse ss, you may need 
            ss.clear(); 
            // to clean up error flags like EOF.
        }
    }
}