使用boost :: iostreams读取特制的数据,然后基于该创建对象并将其附加到列表中

时间:2010-02-03 15:53:42

标签: c++ parsing boost serialization boost-iostreams

我有一个有趣的问题。假设我的文件包含这样的行:

name1[xp,y,z321](a,b,c){text};//comment
#comment
name2(aaaa);

我也有(简化)课程:

class something {
public:
 something(const std::string& name);
 addOptionalParam(const std::string& value);
 addMandatoryParam(const std::string& value);
 setData((const std::string& value);
};

name对应于某些类构造函数的param名称。 []括号中列出的内容是可选的,in()是强制性的,{}之间的所有内容都应该作为字符串。

对于第一行,应该使用“name1”作为名称调用构造函数; 3次调用addOptionalParam,每次用冒号分隔一次;还有3次addMandatoryParam和setData“text”。

我可以弄清楚如何进行评论,但其他一切都是我的错误......

现在我需要一些好的建议如何(或者如果)这是可能的,如果我可以解决如何为简单对象做到这一点,我可以弄清楚如何处理所有额外的血腥细节,如语义正确性。

3 个答案:

答案 0 :(得分:5)

您是否考虑过Boost Spirit等解析器?

答案 1 :(得分:5)

你的描述有点令人困惑(例如你提到“用冒号分隔”,但我没有在输入中看到任何冒号)。我假设你想要的是方括号中的项是可选参数,括号中是必需参数,花括号中是'数据'。

在这种情况下,您的语法似乎是这样的:

func: name optionalParams '(' paramList ')' '{' data '}'

paramList: param |
          paramlist ',' param

optionalParams:  // empty
              | '[' paramList ']'

name: WORD
param: WORD
data: WORD

这是一个简单的语法,Spirit可能会很好地使用它。精神往往导致较大的语法编译时间非常长,但这个语法足够小,编译时间应该非常合理。

显而易见的替代方法是编写一个下降解析器(如递归下降解析器,但在这种情况下,不需要递归)。在这种情况下,你基本上为语法的每个级别编写一个函数,让它读取适当的输入,并返回一个保存它读取的数据的结构(例如一个向量)。例如,optionalParams可能是最难解析的(仅仅因为它是可选的):

typedef std::string param;

std::vector<param> read_optional_params(std::istream &in) { 
    std::vector<param> ret;

    char ch = in.peek();
    if (ch == '[' ) {
        in >> ch;
        param temp;
        while (in >> temp && temp != "]") 
            ret.push_back(temp);
            if ((ch=in.peek) == ',')
                in >> ch;
    }
    return ret;    
}

在顶层,你会有类似的东西:

function read_func(std::istream &in) { 
    std::string name = read_name(in);
    std::vector<param> optional_params = read_optional_params(in);
    std::vector<param> mandatory_params = read_mandatory_params(in);
    std::string data = read_data(in);

    if (in.fail()) {
        // malformed input
    }

    function func = function(name);
    for (int i=0; i<optional_params.size(); i++)
        func.addOptionalParam(optional_params[i]);
    for (int i=0; i<mandatory_params.size(); i++)
        func.addMandatoryParam(mandatoryParams[i]);
    func.setData(data);
    return func;
}

答案 2 :(得分:-1)

哇,哇哇......

我从来不知道这会在其他方面完成,而不是从文件中读取,直接来自Boost的边缘知识,我不知道有什么像boost :: spirit。然而,现在通过文档,我发现它很难遵循,大多数时候它就像“使用real_p”并且没有关于命名空间的信息,所以在哪里找到给定的项目很困惑......但是看看它能做什么完成我真的很惊讶。

我想扩展有关语法的信息(但是我并没有更接近破译如何在代码术语中完成它):

name:可以是任何不以数字开头的字符串,除了小写字母,数字和“_”之外没有任何字符 param:可以是整数,double或只包含'a-z'字符的字符串
数据:大括号之间的任何内容(即使可能,换行符),因此{{{{{}应该产生'{{{{'和{} {} {} {}应该失败(语法上讲)
';':应该作为分隔符和明确的结束,所以它是必须的

其他内容是评论,因为我在示例中看不到如何实现它们。

感谢您的帮助,我希望了解它的发展方向。