无限输入的正则表达式
regular expressions on infinite input
我想使用正则表达式来解析从套接字接收到的数据。
我已经编写了一个自定义套接字迭代器,因此我可以将数据传递给 std
的正则表达式函数。
请记住,理论上数据可能永远不会结束,在发送完整请求后套接字不会关闭,因为客户端期望响应和可能的未来通信。
假设我们有一个非常简单的协议,请求由 START
或 STOP
组成。
真正的协议当然要复杂得多,但为了举例起见,这就可以了。
// A simple regular expression to parse this could be defined like so:
static const std::regex re("^(START|STOP)");
// And parsed using:
std::regex_match(begin, end, result, re); // 1
// or using regex_search
std::regex_search(begin, end, result, re); // 2
假设客户端发送单词 START
,等待 5 秒,然后发送另一个字符,例如 X
。在这种情况下,方法 #1 将在 returning false 之前等待 5 秒。现在假设客户端在原始 START
消息之后没有发送任何内容,方法 #1 永远不会 return.
至于方法 #2:假设您的输入是 XSTART
,解析器似乎不明白永远不会找到有效的匹配项,因为正则表达式以 ^
开头,而且输入是无限的它也永远不会终止。
所以最后,方法 #1 正确识别无效请求,而方法 #2 正确识别有效请求,但是方法 #1 在有效请求时陷入无限循环,而方法 #2 在无效请求时陷入。
这个Minimal, Complete, and Verifiable example说明了问题:
#include <stdio.h>
#include <stdint.h>
#include <iterator>
#include <vector>
#include <regex>
// stdin iterator that goes against all good
// programming practices for the sake of simplicity
class stdin_iter : public std::iterator<std::bidirectional_iterator_tag, char> {
static std::vector<char> buf;
size_t i;
public:
stdin_iter() : i(SIZE_MAX) {}
stdin_iter(size_t i) : i(i) {}
bool operator==(const stdin_iter& o) const { return i == o.i; }
bool operator!=(const stdin_iter& o) const { return i != o.i; }
value_type operator*() const {
while (i >= buf.size()) buf.push_back(getc(stdin));
return buf[i];
}
stdin_iter& operator++() { i++; return *this; }
stdin_iter operator++(int) { stdin_iter r = *this; i++; return r; }
stdin_iter& operator--() { i--; return *this; }
stdin_iter operator--(int) { stdin_iter r = *this; i--; return r; }
};
std::vector<char> stdin_iter::buf;
int main() {
stdin_iter begin(0), end;
std::regex re("^(START|STOP)");
std::match_results<stdin_iter> result;
//bool valid = std::regex_match(begin, end, result, re); // stuck on valid input
//bool valid = std::regex_search(begin, end, result, re); // stuck on invalid input
bool valid = std::regex_search(begin, end, result, re, std::regex_constants::match_continuous); // mostly works
if (valid) printf("valid: %s\n", result[1].str().c_str());
else printf("invalid\n");
}
一个解决方案是在数据停止活动后,例如,在一秒钟不活动后,人为地添加一个结束符。但这会大大增加响应时间,而且感觉不对。
另一种解决方案是编写自定义正则表达式解析器,但为如此简单的问题重新发明轮子似乎有些过分。
有没有更好的方法来完成这项工作?
使用 std::regex_constants::match_continuous
标志,卢克。
我想使用正则表达式来解析从套接字接收到的数据。
我已经编写了一个自定义套接字迭代器,因此我可以将数据传递给 std
的正则表达式函数。
请记住,理论上数据可能永远不会结束,在发送完整请求后套接字不会关闭,因为客户端期望响应和可能的未来通信。
假设我们有一个非常简单的协议,请求由 START
或 STOP
组成。
真正的协议当然要复杂得多,但为了举例起见,这就可以了。
// A simple regular expression to parse this could be defined like so:
static const std::regex re("^(START|STOP)");
// And parsed using:
std::regex_match(begin, end, result, re); // 1
// or using regex_search
std::regex_search(begin, end, result, re); // 2
假设客户端发送单词 START
,等待 5 秒,然后发送另一个字符,例如 X
。在这种情况下,方法 #1 将在 returning false 之前等待 5 秒。现在假设客户端在原始 START
消息之后没有发送任何内容,方法 #1 永远不会 return.
至于方法 #2:假设您的输入是 XSTART
,解析器似乎不明白永远不会找到有效的匹配项,因为正则表达式以 ^
开头,而且输入是无限的它也永远不会终止。
所以最后,方法 #1 正确识别无效请求,而方法 #2 正确识别有效请求,但是方法 #1 在有效请求时陷入无限循环,而方法 #2 在无效请求时陷入。
这个Minimal, Complete, and Verifiable example说明了问题:
#include <stdio.h>
#include <stdint.h>
#include <iterator>
#include <vector>
#include <regex>
// stdin iterator that goes against all good
// programming practices for the sake of simplicity
class stdin_iter : public std::iterator<std::bidirectional_iterator_tag, char> {
static std::vector<char> buf;
size_t i;
public:
stdin_iter() : i(SIZE_MAX) {}
stdin_iter(size_t i) : i(i) {}
bool operator==(const stdin_iter& o) const { return i == o.i; }
bool operator!=(const stdin_iter& o) const { return i != o.i; }
value_type operator*() const {
while (i >= buf.size()) buf.push_back(getc(stdin));
return buf[i];
}
stdin_iter& operator++() { i++; return *this; }
stdin_iter operator++(int) { stdin_iter r = *this; i++; return r; }
stdin_iter& operator--() { i--; return *this; }
stdin_iter operator--(int) { stdin_iter r = *this; i--; return r; }
};
std::vector<char> stdin_iter::buf;
int main() {
stdin_iter begin(0), end;
std::regex re("^(START|STOP)");
std::match_results<stdin_iter> result;
//bool valid = std::regex_match(begin, end, result, re); // stuck on valid input
//bool valid = std::regex_search(begin, end, result, re); // stuck on invalid input
bool valid = std::regex_search(begin, end, result, re, std::regex_constants::match_continuous); // mostly works
if (valid) printf("valid: %s\n", result[1].str().c_str());
else printf("invalid\n");
}
一个解决方案是在数据停止活动后,例如,在一秒钟不活动后,人为地添加一个结束符。但这会大大增加响应时间,而且感觉不对。
另一种解决方案是编写自定义正则表达式解析器,但为如此简单的问题重新发明轮子似乎有些过分。
有没有更好的方法来完成这项工作?
使用 std::regex_constants::match_continuous
标志,卢克。