我使用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 :(得分: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 :(得分:1)
我忍不住注意到这与Boost::property_tree中INFO解析器支持的格式完全相同,但以分号终止的值除外。它应该是微不足道的,以一种从键值中去掉分号的方式来包装它;无论如何,比自己编写输入/输出和处理功能更容易,更不容易出错。
答案 2 :(得分:0)