如何使用qi解析和验证整数的有序列表

|| 我正在解析一个文本文件,大小可能为几GB,由以下几行组成:
11 0.1
14 0.78
532 -3.5
基本上,每行一个int和一个float。整数应该有序且不可为负。我想验证数据是否如前所述,并已将范围内的最小和最大整数返回给我。这是我想出的:
#include <iostream>
#include <string>

#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>

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

namespace my_parsers
{
using namespace qi;
using px::at_c;
using px::val;
template <typename Iterator>
struct verify_data : grammar<Iterator, locals<int>, std::pair<int, int>()>
{
    verify_data() : verify_data::base_type(section)
    {
        section
            =  line(val(0))    [ at_c<0>(_val) = _1]
            >> +line(_a)       [ _a = _1]
            >> eps             [ at_c<1>(_val) = _a]
            ;

        line
            %= (int_ >> other) [
                                   if_(_r1 >= _1)
                                   [
                                       std::cout << _r1 << \" and \"
                                       << _1 << val(\" out of order\\n\")
                                   ]
                               ]
            ;

        other
            = omit[(lit(\' \') | \'\\t\') >> float_ >> eol];
    }
    rule<Iterator, locals<int>, std::pair<int, int>() > section;
    rule<Iterator, int(int)> line;
    rule<Iterator> other;
};
}

using namespace std;
int main(int argc, char** argv)
{
    string input(\"11 0.1\\n\"
                 \"14 0.78\\n\"
                 \"532 -3.6\\n\");

    my_parsers::verify_data<string::iterator> verifier;
    pair<int, int> p;
    std::string::iterator begin(input.begin()), end(input.end());
    cout << \"parse result: \" << boolalpha
         << qi::parse(begin, end, verifier, p) << endl; 
    cout << \"p.first: \" << p.first << \"\\np.second: \" << p.second << endl;
    return 0;
}
我想知道以下内容:  有没有更好的方法来解决这个问题?我使用了继承和合成的属性,局部变量和一些凤凰巫毒。这很棒;学习工具是好的,但我不禁想到可能会有更简单的方法来实现相同的目的:/(在PEG解析器中……)  例如,没有局部变量怎么办? 更多信息:我同时正在解析其他数据格式,因此我想将返回值保留为解析器属性。目前,这是一个std :: pair,其他数据格式在解析时将公开它们自己的std :: pairs,例如,我想将它们填充到std :: vector中。     
已邀请:
        这至少要短很多: 低至28 LOC 没有更多的当地人 不再有融合矢量
at<>
巫术 不再继承属性 没有更多的语法课 不再需要手动迭代 使用期望点(参见
other
)增强解析错误报告 如果您选择为解析器表达式分配
%=
,则该解析器表达式会整齐地合成为
vector<int>
(但是,这可能会提高性能,除了可能分配较大的数组外) 。
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

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

typedef std::string::iterator It;

int main(int argc, char** argv)
{
    std::string input(\"11 0.1\\n\"
            \"14 0.78\\n\"
            \"532 -3.6\\n\");

    int min=-1, max=0;
    {
        using namespace qi;
        using px::val;
        using px::ref;

        It begin(input.begin()), end(input.end());
        rule<It> index = int_ 
            [
                if_(ref(max) < _1)  [ ref(max) = _1 ] .else_ [ std::cout << _1 << val(\" out of order\\n\") ],
                if_(ref(min) <  0)  [ ref(min) = _1 ]
            ] ;

        rule<It> other = char_(\" \\t\") > float_ > eol;

        std::cout << \"parse result: \" << std::boolalpha 
                  << qi::parse(begin, end, index % other) << std::endl; 
    }
    std::cout << \"min: \" << min << \"\\nmax: \" << max << std::endl;
    return 0;
}
奖金 我可能建议从表达式中删除验证,并使其成为独立函数;当然,这会使事情变得更加冗长(而且...更清晰),我的死灵样本使用全局变量...-但我相信您知道如何使用
boost::bind
px::bind
使其更真实 除了以上 甚至免费功能也可降低到27 LOC 不再有凤凰,不再有凤凰包含(编译时间) 在调试版本中不再有凤凰表达式类型使二进制文件膨胀并放慢速度 不再有
var
ref
if_
.else_
和可怜的
operator,
(由于有时不包含在phoenix.hpp中,因此存在重大错误风险(有时)) (轻松移植到c ++ 0x lambda's-立即消除了对全局变量的需求) 。
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
namespace px = boost::phoenix;
namespace qi = boost::spirit::qi;
typedef std::string::iterator It;

int min=-1, max=0, linenumber=0;
void validate_index(int index)
{
    linenumber++;
    if (min < 0)     min = index;
    if (max < index) max = index;
    else             std::cout << index << \" out of order at line \" << linenumber << std::endl;
}

int main(int argc, char** argv)
{
    std::string input(\"11 0.1\\n\"
            \"14 0.78\\n\"
            \"532 -3.6\\n\");
    It begin(input.begin()), end(input.end());

    {
        using namespace qi;

        rule<It> index = int_ [ validate_index ] ;
        rule<It> other = char_(\" \\t\") > float_ > eol;
        std::cout << \"parse result: \" << std::boolalpha 
                  << qi::parse(begin, end, index % other) << std::endl; 
    }
    std::cout << \"min: \" << min << \"\\nmax: \" << max << std::endl;
    return 0;
}
    
        我想更简单的方法是使用标准流操作解析文件,然后循环检查顺序。首先,输入:
typedef std::pair<int, float> value_pair;

bool greater(const value_pair & left, const value_pair & right) {
    return left.first > right.first;
}

std::istream & operator>>(std::istream & stream, value_pair & value) {
    stream >> value.first >> value.second;
    return stream;
}
像这样使用:
std::ifstream file(\"your_file.txt\");
std::istream_iterator<value_pair> it(file);
std::istream_iterator<value_pair> eof;

if(std::adjacent_find(it, eof, greater) != eof) {
    std::cout << \"The values are not ordered\" << std::endl;
}
我发现这要简单得多。     

要回复问题请先登录注册