соответствие строки и скобок переполнению стека

Я использую c ++ для чтения файла и получения значения ключа по имени ключа. Дело в том, что имя ключа может повторяться много раз в этом файле. Они структурированы в следующем формате.

Формат файла данных

Пожалуйста, имейте в виду, что сейчас у меня нет большого контроля над исходным кодом, так как этот файл данных отформатирован.

dictName
{
keyA 9;
keyB 3;
keyC 5;

subDictName
{
keyD 0.57;
keyE 5.23;
}
}

anotherDictName
{
keyG 6;
keyC 1;

subDictName
{
keyF 0.17;
keyE 2.21;
}
}

Я написал следующий код, но обнаружил, что он недостаточно чист, кто-нибудь знает лучшее решение для обработки соответствия скобок в C ++?

Код, который я написал

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
ifstream inf(fileName);
istream_iterator<string> first(inf), last;
vector<string> lines(first, last);

for (unsigned i = 0; i < lines.size(); ++i)
{
if (size_t pos1 = lines[i].find(dictName) != string::npos)
{
size_t len1 = string(dictName).length();
if (!isalnum(lines[i][pos1+len1+1]))
{
unsigned lineSta = 0;
unsigned lineEnd = 0;
for (unsigned j = i+1; j < lines.size(); ++j)
{
if (lines[j].find("{") != string::npos)
{
lineSta = j+1;
break;
}
}
for (unsigned k = lineSta+1; k < lines.size(); ++k)
{
if (lines[k].find("}") != string::npos)
{
lineEnd = k-1;
break;
}
}
for (unsigned l = lineSta; l <= lineEnd; ++l)
{
if (size_t pos2 = lines[l].find(keyName) != string::npos)
{
size_t len2 = string(keyName).length();
if (!isalnum(lines[l][pos2+len2+1]))
{
outputStr = split(lines[l+1], ';')[0];
cout<< "outputStr = " << outputStr << endl;
break;
}
}
}
}
}
}

return 0;
}

0

Решение

Я не мог не заметить, что это тот же формат, который поддерживается парсером INFO в Повысьте :: property_tree, за исключением значений, оканчивающихся точкой с запятой. Это должно быть почти тривиально, чтобы обернуть это таким образом, чтобы отделить точку с запятой от значения ключа; во всяком случае, намного проще и менее подвержен ошибкам, чем сам написание функций ввода / вывода и обработки.

1

Другие решения

Поскольку это существующий формат, я бы начал с поиска существующей программы или библиотеки, которая его читает. В противном случае традиционным решением будет использование Bison и Flex. Я уверен, что Boost и другие современные инструменты тоже можно использовать, но я больше знаком с Bison и Flex.

Чтобы продемонстрировать принцип, вот минимальное решение с использованием Bison и Flex, которое может проанализировать ваш пример входного файла. Возможно, я неправильно понял формат вашего ввода, поэтому используйте его с осторожностью.

Сначала файл Bison, который определяет грамматику для ввода:

%{
#include <iostream>
extern int yylex();
extern void yyerror(char* message);
%}

%token ID INT FLOAT

%%

dicts : dicts dict | /* empty */ ;
dict : ID '{' keys subdict '}' { std::cout << "Done a dict.\n"; } ;
keys : keys key | /* empty */ ;
key : ID INT ';' { std::cout << "Done a key.\n"; };
subdict : ID '{' subkeys '}' { std::cout << "Done a subdict.\n"; } ;
subkeys : subkeys subkey | /* empty */ ;
subkey : ID FLOAT ';' { std::cout << "Done a subkey.\n"; };

%%

void yyerror(char* message) {
std::cout << "Error: " << message << "\n";
}

int main() {
std::cout << "Staring parser...\n";
yyparse();
std::cout << "Parser done.\n";
return 0;
}

И затем файл Flex, который определяет формат отдельных токенов во входных данных:

%{
#include "parser.tab.h"%}

%%

[ \t\n]         { }
[0-9]+\.[0-9]+  { return FLOAT; }
[0-9]+          { return INT; }
[A-Za-z]+       { return ID; }
";"             { return ';'; }
"{"             { return '{'; }
"}"             { return '}'; }

%%

Я получаю этот вывод для вашего входного файла:

Staring parser...
Done a key.
Done a key.
Done a key.
Done a subkey.
Done a subkey.
Done a subdict.
Done a dict.
Done a key.
Done a key.
Done a subkey.
Done a subkey.
Done a subdict.
Done a dict.
Parser done.
1

вы, вероятно, должны изучить рекурсивные алгоритмы

вот ссылка на вики, которая может помочь Парсер рекурсивного спуска

он более сложен для реализации, чем ваш метод, но гораздо более чистый и мощный

0
По вопросам рекламы [email protected]