Я перешел к старому доброму пользовательскому подходу к синтаксическому анализу, когда застрял с регулярным выражением. Это оказалось не так уж и плохо, так как содержимое файла можно довольно аккуратно разбить на токены, а токены можно анализировать в цикле с помощью очень простого конечного автомата. Те, кто хочет проверить, есть фрагмент кода, делающий это с диапазоном -для итераторов ifstream и пользовательского токенизатора потока в моем другом вопросе в Stackoverflow здесь . Эти методы значительно уменьшают сложность создания пользовательского синтаксического анализатора.
Я хотел бы токенизировать содержимое файла в первой части в группах захвата по два, а затем просто построчно. У меня есть полуфункциональное решение -, но я хотел бы узнать, как его улучшить. То есть без «лишней обработки», чтобы -восполнить незнание с группами захвата. Далее некоторые предварительные и в конце более точный вопрос (строка
const std::regex expression("([^:]+?)(^:|$)");
... это тот, о котором я хотел бы спросить в сочетании с обработкой результатов ).
Файлы, которые в основном определены следующим образом:
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
HOW TO INTERPRET THE FOLLOWING SECTION OF ROWS
[DATA ROW 1]
[DATA ROW 2]
...
[DATA ROW n]
Где каждая из строк данных состоит из определенного количества либо целых чисел, либо чисел с плавающей запятой, разделенных пробелом. Каждая строка имеет столько же чисел, сколько и другие (, например. в каждой строке может быть четыре целых числа ). Таким образом, «раздел интерпретации» в основном сообщает этот формат в виде простого текста в одной строке.
У меня есть почти работающее решение, которое читает такие файлы, как этот:
int main()
{
std::ifstream file("xyz", std::ios_base::in);
if(file.good())
{
std::stringstream file_memory_buffer;
file_memory_buffer << file.rdbuf();
std::string str = file_memory_buffer.str();
file.close();
const std::regex expression("([^:]+?)(^:|$)");
std::smatch result;
const std::sregex_token_iterator end;
for(std::sregex_token_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
std::cout << (*i) << std::endl;
}
}
return EXIT_SUCCESS;
}
С регулярным выражением, определенным expression
, он теперь печатает части
файла определения, затем часть интерпретации, а затем строки данных одну за другой. Если я изменю регулярное выражение на
"([^:]+?)(:|$)"
... он печатает все строки, размеченные группами по одной, почти так, как мне бы хотелось, но как разбить первую часть на группы по две, а остальные строки за строкой?
Любые указатели, код, объяснения действительно приветствуются. Спасибо.
Как уже отмечалось Тому Керру , но некоторые дополнительные моменты, это также репетиция или ката кодирования, если хотите, чтобы не писать собственный синтаксический анализатор, а посмотреть, смогу ли я --или мы мог:-)--выполнить это с помощью регулярного выражения. Я знаю, что регулярное выражение — не самая эффективная вещь, но это не имеет значения.
Я надеюсь получить что-то вроде списка кортежей информации заголовка (кортежа размера 2 ), затем строки INTERPRET (кортежа размера 1 ), который я мог бы использовать для выбора что делать со строками данных (кортеж размера 1 ).
Да, строка «КАК ИНТЕРПРЕТИТЬ» содержится в наборе хорошо -определенных строк, и я мог бы просто читать строку за строкой с самого начала, разбивая строки по пути, пока не встретится одна из строк ИНТЕРПРЕТ. Я знаю, что это решение с регулярными выражениями не самый эффективный метод, но больше похоже на кодирование ката, чтобы заставить себя писать что-то еще, чем клиентские синтаксические анализаторы (, и в последний раз я писал на C++ довольно давно, так что это репетиция иначе тоже ).
Мне удалось получить доступ к кортежам (в контексте этого вопроса ), изменив тип итератора, например
const std::sregex_iterator end;
for(std::sregex_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
std::cout << "0: " << (*i)[0] << std::endl;
std::cout << "1: " << (*i)[1] << std::endl;
std::cout << "2: " << (*i)[2] << std::endl;
std::cout << "***" << std::endl;
}
Хотя это все еще далеко от того, что я хотел бы иметь, что-то не так с регулярным выражением, которое я пытаюсь использовать. В любом случае, эта новая находка, еще один вид итератора, тоже помогает.