我是Spirit :: Qi的新手,我正在尝试编写一个简单的Wavefront Obj解析器。我已经按照Boost :: Spirit文档站点(link)的教程进行了操作,并且我使大多数内联规则正常工作。我已经开始尝试使用语法,但我似乎无法让它们正常工作。过了一会儿我确实把它编译好了,但解析失败了。我真的不知道我做错了什么。
首先,我创建了一个包含以下内容的简单文本文件:
v -1.5701 33.8087 0.3592
v -24.0119 0.0050 21.7439
v 20.8717 0.0050 21.7439
v 20.8717 0.0050 -21.0255
v -24.0119 0.0050 -21.0255
v -1.5701 0.0050 0.3592
只是为了确定:读取输入文件可以正常工作。
我写了一个应该解析输入字符串的小函数,但由于某种原因它失败了:
bool Model::parseObj( std::string &data, std::vector<float> &v )
{
struct objGram : qi::grammar<std::string::const_iterator, float()>
{
objGram() : objGram::base_type(vertex)
{
vertex = 'v' >> qi::float_
>> qi::float_
>> qi::float_;
}
qi::rule<std::string::const_iterator, float()> vertex;
};
objGram grammar;
return qi::phrase_parse( data.cbegin(), data.cend(),
grammar, iso8859::space, v );
}
qi :: phrase_parse一直返回false,而std :: vector v最后仍为空...
有什么建议吗?
编辑:
添加空格标签后(是正确的名称?),只有第一个'v'被添加到编码为float(118.0f)的std :: vector中,但实际的数字不会被添加。我的猜测是我的规则不正确。我想只添加数字并跳过v。
这是我修改过的功能:
bool Model::parseObj( std::string &data, std::vector<float> &v )
{
struct objGram : qi::grammar<std::string::const_iterator, float(), iso8859::space_type>
{
objGram() : objGram::base_type(vertex)
{
vertex = qi::char_('v') >> qi::float_
>> qi::float_
>> qi::float_;
}
qi::rule<std::string::const_iterator, float(), iso8859::space_type> vertex;
} objGrammar;
return qi::phrase_parse( data.cbegin(), data.cend(),
objGrammar, iso8859::space, v );
}
答案 0 :(得分:2)
您的规则声明了错误的公开属性。改变它:
qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> vertex;
但是,既然你没有在任何东西上模板化你的语法结构(比如iterator / skipper类型),那么拥有一个语法结构是没有意义的。相反,让phrase_parse
只是简单地推导出迭代器,队长和规则类型并写入:
bool parseObj(std::string const& data, std::vector<float> &v )
{
return qi::phrase_parse(
data.cbegin(), data.cend(),
'v' >> qi::float_ >> qi::float_ >> qi::float_,
qi::space, v);
}
我认为你会同意这一点。作为奖励,由于自动属性传播规则的强大功能,它“正常工作”(TM)。
然而,看到你的语法,你肯定希望看到这些:
How to parse space-separated floats in C++ quickly?显示如何解析结构的向量
struct float3 {
float x,y,z;
};
typedef std::vector<float3> data_t;
很少或没有额外的工作。哦,它会根据竞争的fscanf
和atod
调用对阅读500Mb文件的精神方法进行基准测试。因此,它一次解析多行:)
即使您最终分配给单精度qi::double_
变量,也请使用qi::float_
解析器而不是float
。请参阅Boost spirit floating number parser precision