регулярные выражения на бесконечном вводе - PullRequest
0 голосов
/ 09 декабря 2018

Я бы хотел использовать регулярные выражения для анализа данных, полученных из сокета.
Я написал собственный итератор сокета, чтобы я мог передавать данные в регулярные выражения 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 будет ждать 5 секунд, прежде чем вернуть false.Теперь представьте, что клиент ничего не отправляет после исходного сообщения START, метод # 1 никогда не вернется.
Что касается метода # 2: допустим, ваш ввод XSTART, синтаксический анализатор, похоже, не понимаетчто действительное совпадение никогда не будет найдено, потому что регулярное выражение начинается с ^, а поскольку входное значение бесконечно, оно также никогда не завершится.
Таким образом, в методе end # 1 правильно определяются неверные запросы, в то время как метод # 2 правильно определяет действительныезапросов, но метод # 1 застревает в бесконечном цикле при действительном запросе, а метод # 2 застревает в недопустимом запросе.

Этот пример Minimal, Complete и Verifiable демонстрирует проблему:

#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");
}

Одним из решений является добавление искусственного окончания данных после, например, секунды бездействия.Но это значительно увеличивает время отклика и просто не кажется правильным.
Еще одно решение - написать собственный синтаксический анализатор регулярных выражений, но, кажется, излишне изобретать колесо для такой простой проблемы.
Есть ли лучший способсделать эту работу?

1 Ответ

0 голосов
/ 10 декабря 2018

Используйте флаг std::regex_constants::match_continuous, Люк.

...