:: boost :: spirit:+ alnum_p和连字符

时间:2015-11-07 02:18:06

标签: c++ parsing boost boost-spirit

现在我有这个提升::精神模式:

        str_p("url(") >> !( str_p("'") | str_p("\"") ) >> ("#") >>
        ((+alnum_p)[assign_a(o_rPaintUri)] >> 
        !( str_p("'") | str_p("\"") ) >> str_p(")")

这样可以解析url(#myRadialGradient)之类的内容,但是如果有url(#my-RadialGradient4)这样的连字符则不起作用。 我尝试过像(+alnum_p | '-')[assign_a(o_rPaintUri)]这样的东西,但它没有用。

任何人都有提示如何做到这一点?

由于

1 个答案:

答案 0 :(得分:2)

那是精神经典(又名.v1.x)。
PS。 没有任何线索,但您可以尝试(+(alnum_p | ch_p('-')))而不是(+alnum_p | '-')

你应该进入本世纪,并使用Spirit V2(自取代v1以来大约十年):

Spirit V2

<强> Live On Coliru

#include <boost/spirit/include/qi.hpp>

int main() {
    for (std::string const sample : {
            "url(#myRadialGradient)",
            "url(#my-RadialGradient4)",
            "url('#my-RadialGradient4')",
            "url(\"#my-RadialGradient4\")",
            })
    {
        std::cout << " -- parsing '" << sample << "'\n";
        std::string o_rPaintUri;

        bool ok;
        {
            using namespace boost::spirit::qi;
            ok = parse(sample.begin(), sample.end(),
                    "url(" >> -char_("'\"") >> "#" >> +(alnum|char_('-')) >> -char_("'\"") >> ")",
                    o_rPaintUri);
        }

        if (ok)
            std::cout << "Parsed: '" << o_rPaintUri << "'\n";
        else
            std::cout << "Parse failed\n";
    }
}

打印

-- parsing 'url(#myRadialGradient)'
Parsed: 'myRadialGradient'
-- parsing 'url(#my-RadialGradient4)'
Parsed: 'my-RadialGradient4'
-- parsing 'url('#my-RadialGradient4')'
Parsed: ''my-RadialGradient4''
-- parsing 'url("#my-RadialGradient4")'
Parsed: '"my-RadialGradient4"'

精神X3

相同,但将qi替换为x3。我建议做些改进:

  • 现在支持任何带引号的字符(引号字符除外)
  • 现在期望所有语法元素并报告有用的错误

<强> Live On Coliru

#include <boost/spirit/home/x3.hpp>
#include <boost/exception/all.hpp>
#include <iostream>

namespace x3 = boost::spirit::x3;

int main() {
    for (std::string const sample : {
            "url(#myRadialGradient)",
            "url(#my-RadialGradient4)",
            "url('#my-RadialGradient4')",
            "url(\"#my-RadialGradient4\")",
            // extra
            "url('#my-RadialGradient4\")",
            "url('#my-Radial_Gradient4')",
            "url('#my-Radial_Gradient4'",
            "url(oops)",
            "url('oops')",
            "url(\"oops\")",
            "oops",
            })
    {
        std::cout << " -- parsing " << sample << "\n";
        std::string o_rPaintUri;

        bool ok = false;
        try {
            using namespace x3;

            auto q = [](auto quote) { return quote > as_parser('#') > *(char_ - quote) > quote; };

            auto u = rule<struct url, std::string> { "#anchor|'#anchor'|\"#anchor\"" } // FOR ERROR INFO ONLY
                   = q("'") | q('"') | '#' >> *~char_(')');

            ok = parse(sample.begin(), sample.end(), eps > "url(" > u > ")", o_rPaintUri);

            if (ok)
                std::cout << "Parsed: '" << o_rPaintUri << "'\n";
            else
                std::cout << "Parse failed\n";

        } catch (x3::expectation_failure<std::string::const_iterator> const& e) {
            std::cout << "    Error: '" << std::string(e.where(), sample.end()) << "', expecting " << e.which() << "\n";
        }

    }
}

打印

-- parsing url(#myRadialGradient)
Parsed: 'myRadialGradient'
-- parsing url(#my-RadialGradient4)
Parsed: 'my-RadialGradient4'
-- parsing url('#my-RadialGradient4')
Parsed: 'my-RadialGradient4'
-- parsing url("#my-RadialGradient4")
Parsed: 'my-RadialGradient4'
-- parsing url('#my-RadialGradient4")
    Error: '', expecting "'"
-- parsing url('#my-Radial_Gradient4')
Parsed: 'my-Radial_Gradient4'
-- parsing url('#my-Radial_Gradient4'
    Error: '', expecting ')'
-- parsing url(oops)
    Error: 'oops)', expecting #anchor|'#anchor'|"#anchor"
-- parsing url('oops')
    Error: 'oops')', expecting '#'
-- parsing url("oops")
    Error: 'oops")', expecting '#'
-- parsing oops
    Error: 'oops', expecting "url("