从连续的字符串流中提取线
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
数组做这样的事情。这是完全愚蠢和万无一失的。与 find
和 substring
方法相比,这很可能在速度上损失了几分,但更容易正确。
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.
}
}
}
我想从连续的字符串数据流中提取行。但是数据格式不正确,我想丢弃提取的行,这样内存就不会越界。
比如我的串口输出是这样的:
第 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
数组做这样的事情。这是完全愚蠢和万无一失的。与 find
和 substring
方法相比,这很可能在速度上损失了几分,但更容易正确。
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.
}
}
}