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

时间:2016-07-07 16:55:27

标签: c++ string stl stringstream

我想从连续的字符串数据流中提取行。但数据格式不正确,我想丢弃提取的行,以便内存不会超出限制。

例如,我有串口输出,如:

批次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()并使用类似&#39; popline()&#39;相反,如果它存在。

2 个答案:

答案 0 :(得分:0)

从评论中获取提示,我想出了我自己的popline(),它不使用stringstream。感谢您的评论。

// 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...
    }
}

答案 1 :(得分:0)

πάνταῥεῖ暗示了OP的第一次切割是什么。

while(getline(ss, oneline))

最终点击ss的结尾并设置EOF错误标志。一旦发生这种情况,在使用clear确认错误标志之前,流将不会执行任何操作。

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

我认为OP可能想要更原始一点。我通常使用char函数中的read数组执行此类操作。这完全是愚蠢和万无一失的。与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.
        }
    }
}