【问题标题】:Extracting lines from continuous flow of strings从连续的字符串流中提取线条
【发布时间】:2016-07-07 16:55:26
【问题描述】:

我想从连续的字符串数据流中提取行。但是数据格式不正确,我想丢弃提取的行,以免内存超出范围。

例如,我有这样的串口输出:

第 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()' 的东西,如果它存在的话。

【问题讨论】:

  • 不确定,但尝试在您的内部 while() 循环之后调用 ss.clear()
  • 为什么不用std::deque 来保存行(每行一个std::string)?您想要的是一个“循环缓冲区”,而流类的设计并非如此。 (标准库中也没有其他功能。)

标签: c++ string stl stringstream


【解决方案1】:

从 cmets 获得提示,我想出了自己的 popline(),它不使用 stringstream。谢谢你们的cmets。

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

【讨论】:

    【解决方案2】:

    πάντα ῥεῖ暗示了什么扼杀了 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.
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多