制约了现有Boost.Spirit real_parser(有策略) [英] Constraining the existing Boost.Spirit real_parser (with a policy)
问题描述
我要解析浮动,但不允许NaN值,所以我产生从默认策略继承和政策,创建一个 real_parser
与它:
//使用boost ::精神::齐:: {real_parser,real_policies,
// phrase_parse,double_,char_};模板< typename的T>
结构no_nan_policy:real_policies< T>
{
模板< typename的我,类型名A>
静态布尔
parse_nan(I和;,我常数和放大器,A安培;){
返回false;
}
};real_parser<双,no_nan_policy<双> > no_nan;//然后我可以使用no_nan解析,如下面的语法
布尔OK = phrase_parse(第一,最后,
no_nan [REF(VALA)= _1]>>烧焦_(@)GT;> double_ [REF(B)= _1]
空间);
但现在我的也要确保以 no_nan
解析字符串的总长度不超过4,即1.23或0.123,甚至2.e6或INF就行了,3.2323不是,也不是男。我不能这样做,在政策,这看起来分离左侧的圆点/右的 parse_n
/ parse_frac_n
部分如果无法通信( ...干净的),他们将不得不因为总的长度是相关的。
的想法,然后是扩展 real_parser
(在升压/精神的/ home /气/数字/ real.hpp
)和包裹解析
法 - 但这类没有方法。旁边的 real_parser
是 any_real_parser
结构而确实的有解析
,但是这两种结构似乎并没有任何明显的方式进行交互。
有没有一种方法可以轻松地注入我自己的解析(),做一些pre-检查,然后调用的真正的解析(返回的boost ::精神::齐:: any_real_parser< T,RealPolicy> ::解析(...)
),然后坚持给定的政策?写一个新的解析器将是一个不得已的方法,但我希望有一个更好的办法。
(使用Boost 1.55,即精神2.5.2,用C ++ 11)
看来我那么近,即只是为了double_解析器的一些变化,我会做。这可能会是一个很多比增加一个新的语法,因为所有其他解析是这样做的方式更容易维护。 - 身背<一个href=\"http://stackoverflow.com/questions/30375750/extending-the-existing-boost-spirit-real-parser-with-a-policy-plus-a-wrapped-par#comment48844034_30375750\">7小时前
块引用>更易于维护将不会再写分析器都没有。
您基本上要解析一个浮点数(精神已经得到了你覆盖的),但后来应用一些验证。我会做验证在语义动作:
原料[double_ [_val = _1] [_pass = isnan _(_ VAL)及!&安培; PX ::大小(_1)&LT; = 4]
这就是它。
说明
解剖:
double_ [_val = _1]
解析一个双并将其分配给暴露的属性作为usual¹原料[解析]
匹配封闭的解析器
的但公开原料来源迭代器区间为属性!
[_pass = isnan _(_ VAL)及!&安培; PX ::大小(_1)&LT; = 4]
- 部分业务这个语义动作附加到
原料[]
解析器。因此,
_1
现指已解析的原始迭代器范围双_
_val
已经包含了的成功匹配的夹生的价值双_
_pass
是,我们可以设置为false精神环境标志,使解析失败。现在唯一剩下的事情就是将其结合在一起。让我们的延迟版本
:: isnan
:的boost ::凤::功能&LT; decltype(安培; :: isnan)GT; isnan _(安培; :: isnan);
我们是好去。
测试程序
<大骨节病> 住在Coliru 骨节病>
的#include&LT;升压/精神/有/ qi.hpp&GT;
#包括LT&;升压/精神/有/ phoenix.hpp&GT;
#包括LT&;&CMATH GT;
#包括LT&;&iostream的GT;诠释的main()
{
使用它=标准::字符串::为const_iterator; 汽车my_fpnumber = [] {// TODO封装在一个语法结构
使用空间boost ::精神::补气;
使用boost ::凤凰::大小; 静态的boost ::凤::功能&LT; decltype(安培; :: isnan)GT; isnan _(安培; :: isnan); 返回规则&LT;它,双()&GT; (
原料[double_ [_val = _1]] [_pass = isnan _(_ VAL)及!&放大器;大小(_1)&LT; = 4]
);
}(); 对于(标准::字符串常量小号:{1.23,0.123,2.e6,INF,3.2323,楠})
{
它F = s.begin(),L = s.end(); 双重效果;
如果(解析(F,L,my_fpnumber,结果))
性病::法院LT&;&LT; 解析成功:&LT;&LT;小号所述&;&下; ' - &gt;中与所述;&下;结果&LT;&LT; \\ n;
其他
性病::法院LT&;&LT; 解析拒绝:'&LT;&LT;小号所述&;&下; '在'&LT;&LT;标准::字符串(F,L)LT;&LT; '\\ n;
}
}打印
解析成功:'1.23' - &GT; 1.23
解析成功:0.123 - &GT; 0.123
解析成功:2.e6' - &GT; 2E + 06
解析成功:INF - &GT; INF
解析拒绝:3.2323在3.2323
解析拒绝:'南'的'南'¹的分配必须要因为我们使用语义动作,并明确在这里完成他们通常燮preSS自动属性传播
I want to parse a float, but not allow NaN values, so I generate a policy which inherits from the default policy and create a
real_parser
with it:// using boost::spirit::qi::{real_parser,real_policies, // phrase_parse,double_,char_}; template <typename T> struct no_nan_policy : real_policies<T> { template <typename I, typename A> static bool parse_nan(I&, I const&, A&) { return false; } }; real_parser<double, no_nan_policy<double> > no_nan; // then I can use no_nan to parse, as in the following grammar bool ok = phrase_parse(first, last, no_nan[ref(valA) = _1] >> char_('@') >> double_[ref(b) = _1], space);
But now I also want to ensure that the overall length of the string parsed with
no_nan
does not exceed 4, i.e. "1.23" or ".123" or even "2.e6" or "inf" is ok, "3.2323" is not, nor is "nan". I can not do that in theparse_n
/parse_frac_n
section of the policy, which separately looks left/right of the dot and can not communicate (...cleanly), which they would have to since the overall length is relevant.The idea then was to extend
real_parser
(inboost/spirit/home/qi/numeric/real.hpp
) and wrap theparse
method -- but this class has no methods. Next toreal_parser
is theany_real_parser
struct which does haveparse
, but these two structs do not seem to interact in any obvious way.Is there a way to easily inject my own parse(), do some pre-checks, and then call the real parse (
return boost::spirit::qi::any_real_parser<T, RealPolicy>::parse(...)
) which then adheres to the given policies? Writing a new parser would be a last-resort method, but I hope there is a better way.(Using Boost 1.55, i.e. Spirit 2.5.2, with C++11)
解决方案It seems I am so close, i.e. just a few changes to the double_ parser and I'd be done. This would probably be a lot more maintainable than adding a new grammar, since all the other parsing is done that way. – toting 7 hours ago
Even more maintainable would be to not write another parser at all.
You basically want to parse a floating point numbers (Spirit has got you covered) but apply some validations afterward. I'd do the validations in a semantic action:
raw [ double_ [_val = _1] ] [ _pass = !isnan_(_val) && px::size(_1)<=4 ]
That's it.
Explanations
Anatomy:
double_ [_val = _1]
parses a double and assigns it to the exposed attribute as usual¹raw [ parser ]
matches the enclosedparser
but exposes the raw source iterator range as an attribute
[ _pass = !isnan_(_val) && px::size(_1)<=4 ]
- the business part!This semantic action attaches to the
raw[]
parser. Hence
_1
now refers to the raw iterator range that already parsed thedouble_
_val
already contains the "cooked" value of a successful match ofdouble_
_pass
is a Spirit context flag that we can set to false to make parsing fail.Now the only thing left is to tie it all together. Let's make a deferred version of
::isnan
:boost::phoenix::function<decltype(&::isnan)> isnan_(&::isnan);
We're good to go.
Test Program
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> #include <cmath> #include <iostream> int main () { using It = std::string::const_iterator; auto my_fpnumber = [] { // TODO encapsulate in a grammar struct using namespace boost::spirit::qi; using boost::phoenix::size; static boost::phoenix::function<decltype(&::isnan)> isnan_(&::isnan); return rule<It, double()> ( raw [ double_ [_val = _1] ] [ _pass = !isnan_(_val) && size(_1)<=4 ] ); }(); for (std::string const s: { "1.23", ".123", "2.e6", "inf", "3.2323", "nan" }) { It f = s.begin(), l = s.end(); double result; if (parse(f, l, my_fpnumber, result)) std::cout << "Parse success: '" << s << "' -> " << result << "\n"; else std::cout << "Parse rejected: '" << s << "' at '" << std::string(f,l) << "'\n"; } }
Prints
Parse success: '1.23' -> 1.23 Parse success: '.123' -> 0.123 Parse success: '2.e6' -> 2e+06 Parse success: 'inf' -> inf Parse rejected: '3.2323' at '3.2323' Parse rejected: 'nan' at 'nan'
¹ The assignment has to be done explicitly here because we use semantic actions and they normally suppress automatic attribute propagation
这篇关于制约了现有Boost.Spirit real_parser(有策略)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!