gpt4 book ai didi

c++ - 使用 boost::program_options 来解析文本文件是个好主意吗?

转载 作者:搜寻专家 更新时间:2023-10-30 23:58:27 24 4
gpt4 key购买 nike

我必须处理大量语法和语义定义良好的文件,例如:

  • 第一行是带有特殊信息的标题
  • 其他行在行首包含一个键值,告诉您如何解析和处理该行的内容
  • 如果有评论,它以给定的标记开头
  • 等...

现在 boost::program_options,据我所知,做的工作几乎相同,但我只关心导入那些文本文件的内容,中间没有任何额外的工作,只需解析它并将其存储在我的数据结构中。

对我来说关键的一步是我希望能够用以下方法进行解析:

  • 正则表达式,因为我需要检测不同的语义,我真的无法想象另一种方法来做到这一点
  • 错误检查(损坏的文件,即使在解析整个文件后仍不匹配的 key ,等等......)

那么,我可以使用这个库来完成这项工作吗?有更实用的方法吗?

最佳答案

好的, spirit 语法的起点

_Name    = "newmtl" >> lexeme [ +graph ];
_Ns = "Ns" >> double_;
_Ka = "Ka" >> double_ >> double_ >> double_;
_Kd = "Kd" >> double_ >> double_ >> double_;
_Ks = "Ks" >> double_ >> double_ >> double_;
_d = "d" >> double_;
_illum %= "illum" >> qi::int_ [ _pass = (_1>=0) && (_1<=10) ];

comment = '#' >> *(char_ - eol);

statement=
comment
| _Ns [ bind(&material::_Ns, _r1) = _1 ]
| _Ka [ bind(&material::_Ka, _r1) = _1 ]
| _Kd [ bind(&material::_Kd, _r1) = _1 ]
| _Ks [ bind(&material::_Ks, _r1) = _1 ]
| _d [ bind(&material::_d, _r1) = _1 ]
| _illum [ bind(&material::_illum, _r1) = _1 ]
;

_material = -comment % eol
>> _Name [ bind(&material::_Name, _val) = _1 ] >> eol
>> -statement(_val) % eol;

start = _material % -eol;

我只从您的示例文件中实现了 MTL 文件子集语法。

注意:这是一个相当简单的语法。但是,你知道,首先是第一件事。实际上我可能会考虑使用 the keyword list parser from the spirit repository .它可以为不同的“字段类型”“要求”一定数量的出现。

注意:Spirit Karma(以及大约 50 行其他代码)仅用于演示目的。

具有以下内容的untitled.mtl

# Blender MTL File: 'None'
# Material Count: 2

newmtl None
Ns 0
Ka 0.000000 0.000000 0.000000
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2
# Added just for testing:

newmtl Demo
Ns 1
Ks 0.9 0.9 0.9
d 42
illum 7

输出读取

phrase_parse -> true
remaining input: ''
void dump(const T&) [with T = std::vector<blender::mtl::material>]
-----
material {
Ns:0
Ka:{r:0,g:0,b:0}
Kd:{r:0.8,g:0.8,b:0.8}
Ks:{r:0.8,g:0.8,b:0.8}
d:1
illum:2(Highlight on)
}
material {
Ns:1
Ka:(unspecified)
Kd:(unspecified)
Ks:{r:0.9,g:0.9,b:0.9}
d:42
illum:7(Transparency: Refraction on/Reflection: Fresnel on and Ray trace on)
}
-----

这是列表

#define BOOST_SPIRIT_USE_PHOENIX_V3
#define BOOST_SPIRIT_DEBUG

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp> // for debug output/streaming
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

namespace qi = boost::spirit::qi;
namespace phx= boost::phoenix;

namespace wavefront { namespace obj
{
} }

namespace blender { namespace mtl // material?
{
struct Ns { int exponent; }; // specular exponent
struct Reflectivity { double r, g, b; };

using Name = std::string;
using Ka = Reflectivity;
using Kd = Reflectivity;
using Ks = Reflectivity;

using dissolve_factor = double;
enum class illumination_model {
color, // 0 Color on and Ambient off
color_ambient, // 1 Color on and Ambient on
highlight, // 2 Highlight on
reflection_ray, // 3 Reflection on and Ray trace on
glass_ray, // 4 Transparency: Glass on
// Reflection: Ray trace on
fresnel_ray, // 5 Reflection: Fresnel on and Ray trace on
refract_ray, // 6 Transparency: Refraction on
// Reflection: Fresnel off and Ray trace on
refract_ray_fresnel,// 7 Transparency: Refraction on
// Reflection: Fresnel on and Ray trace on
reflection, // 8 Reflection on and Ray trace off
glass, // 9 Transparency: Glass on
// Reflection: Ray trace off
shadow_invis, // 10 Casts shadows onto invisible surfaces
};

struct material
{
Name _Name;
boost::optional<Ns> _Ns;
boost::optional<Reflectivity> _Ka;
boost::optional<Reflectivity> _Kd;
boost::optional<Reflectivity> _Ks;
boost::optional<dissolve_factor> _d;
boost::optional<illumination_model> _illum;
};

using mtl_file = std::vector<material>;

///////////////////////////////////////////////////////////////////////
// Debug output helpers
std::ostream& operator<<(std::ostream& os, blender::mtl::illumination_model o)
{
using blender::mtl::illumination_model;
switch(o)
{
case illumination_model::color: return os << "0(Color on and Ambient off)";
case illumination_model::color_ambient: return os << "1(Color on and Ambient on)";
case illumination_model::highlight: return os << "2(Highlight on)";
case illumination_model::reflection_ray: return os << "3(Reflection on and Ray trace on)";
case illumination_model::glass_ray: return os << "4(Transparency: Glass on/Reflection: Ray trace on)";
case illumination_model::fresnel_ray: return os << "5(Reflection: Fresnel on and Ray trace on)";
case illumination_model::refract_ray: return os << "6(Transparency: Refraction on/Reflection: Fresnel off and Ray trace on)";
case illumination_model::refract_ray_fresnel: return os << "7(Transparency: Refraction on/Reflection: Fresnel on and Ray trace on)";
case illumination_model::reflection: return os << "8(Reflection on and Ray trace off)";
case illumination_model::glass: return os << "9(Transparency: Glass on/Reflection: Ray trace off)";
case illumination_model::shadow_invis: return os << "10(Casts shadows onto invisible surfaces)";
default: return os << "ILLEGAL VALUE";
}
}

std::ostream& operator<<(std::ostream& os, blender::mtl::Reflectivity const& o)
{
return os << "{r:" << o.r << ",g:" << o.g << ",b:" << o.b << "}";
}

std::ostream& operator<<(std::ostream& os, blender::mtl::material const& o)
{
using namespace boost::spirit::karma;
return os << format("material {"
"\n\tNs:" << (auto_ | "(unspecified)")
<< "\n\tKa:" << (stream | "(unspecified)")
<< "\n\tKd:" << (stream | "(unspecified)")
<< "\n\tKs:" << (stream | "(unspecified)")
<< "\n\td:" << (stream | "(unspecified)")
<< "\n\tillum:" << (stream | "(unspecified)")
<< "\n}", o);
}
} }

BOOST_FUSION_ADAPT_STRUCT(blender::mtl::Reflectivity,(double, r)(double, g)(double, b))
BOOST_FUSION_ADAPT_STRUCT(blender::mtl::Ns, (int, exponent))
BOOST_FUSION_ADAPT_STRUCT(blender::mtl::material,
(boost::optional<blender::mtl::Ns>, _Ns)
(boost::optional<blender::mtl::Ka>, _Ka)
(boost::optional<blender::mtl::Kd>, _Kd)
(boost::optional<blender::mtl::Ks>, _Ks)
(boost::optional<blender::mtl::dissolve_factor>, _d)
(boost::optional<blender::mtl::illumination_model>, _illum))

namespace blender { namespace mtl { namespace parsing
{
template <typename It>
struct grammar : qi::grammar<It, qi::blank_type, mtl_file()>
{
template <typename T=qi::unused_type> using rule = qi::rule<It, qi::blank_type, T>;

rule<Name()> _Name;
rule<Ns()> _Ns;
rule<Reflectivity()> _Ka;
rule<Reflectivity()> _Kd;
rule<Reflectivity()> _Ks;
rule<dissolve_factor()> _d;
rule<illumination_model()> _illum;

rule<mtl_file()> start;
rule<material()> _material;
rule<void(material&)> statement;
rule<> comment;

grammar() : grammar::base_type(start)
{
using namespace qi;
using phx::bind;
using blender::mtl::material;

_Name = "newmtl" >> lexeme [ +graph ];
_Ns = "Ns" >> double_;
_Ka = "Ka" >> double_ >> double_ >> double_;
_Kd = "Kd" >> double_ >> double_ >> double_;
_Ks = "Ks" >> double_ >> double_ >> double_;
_d = "d" >> double_;
_illum %= "illum" >> qi::int_ [ _pass = (_1>=0) && (_1<=10) ];

comment = '#' >> *(char_ - eol);

statement=
comment
| _Ns [ bind(&material::_Ns, _r1) = _1 ]
| _Ka [ bind(&material::_Ka, _r1) = _1 ]
| _Kd [ bind(&material::_Kd, _r1) = _1 ]
| _Ks [ bind(&material::_Ks, _r1) = _1 ]
| _d [ bind(&material::_d, _r1) = _1 ]
| _illum [ bind(&material::_illum, _r1) = _1 ]
;

_material = -comment % eol
>> _Name [ bind(&material::_Name, _val) = _1 ] >> eol
>> -statement(_val) % eol;

start = _material % -eol;

BOOST_SPIRIT_DEBUG_NODES(
(start)
(statement)
(_material)
(_Name) (_Ns) (_Ka) (_Kd) (_Ks) (_d) (_illum)
(comment))
}

};

} } }

#include <fstream>

template <typename T>
void dump(T const& data)
{
using namespace boost::spirit::karma;
std::cout << __PRETTY_FUNCTION__
<< "\n-----\n"
<< format(stream % eol, data)
<< "\n-----\n";
}

void testMtl(const char* const fname)
{
std::ifstream mtl(fname, std::ios::binary);
mtl.unsetf(std::ios::skipws);
boost::spirit::istream_iterator f(mtl), l;

using namespace blender::mtl::parsing;
static const grammar<decltype(f)> p;

blender::mtl::mtl_file data;
bool ok = qi::phrase_parse(f, l, p, qi::blank, data);

std::cout << "phrase_parse -> " << std::boolalpha << ok << "\n";
std::cout << "remaining input: '" << std::string(f,l) << "'\n";

dump(data);
}

int main()
{
testMtl("untitled.mtl");
}

关于c++ - 使用 boost::program_options 来解析文本文件是个好主意吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20443391/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com