c++ - 创建用于检索字符串 vector 的语法

标签 c++ parsing boost boost-spirit text-parsing

我有一个包含表单数据的文件:

fractal mand1 {
    ;lkkj;kj;
}

fractal mand2 {
    if (...) {
        blablah;
    }
}

fractal julia1 {
    a = ss;
}

我想提取数据容器的名称,所以我想在特定情况下检索包含 mand1mand2julia1.

我已经阅读了有关 parsing a number list into a vector 的示例, 但我想在单独的文件中维护语法。

我创建了一个表示语法的结构,然后使用它来解析包含数据的字符串。我希望输出像

mand1
mand2
julia1

取而代之的是

mand1 {
        ;lkkj;kj;
    }

    fractal mand2 {
        if (...) {
            blablah;
        }
    }

    fractal julia1 {
        a = ss;
    }

我的解析器识别第一个 fractal 术语,但随后它将文件的其余部分解析为单个字符串项,而不是按我的需要解析它。

我做错了什么?

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <vector>
#include <iostream>

using boost::spirit::ascii::space;
using boost::spirit::ascii::space_type;
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::lit;
using boost::spirit::qi::lexeme;
using boost::spirit::qi::skip;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::no_case;
using boost::spirit::qi::rule;

typedef std::string::const_iterator sit;

template <typename Iterator>
struct FractalListParser : boost::spirit::qi::grammar<Iterator, std::vector<std::string>(), boost::spirit::ascii::space_type> {
    FractalListParser() : FractalListParser::base_type(start)   {

        no_quoted_string %= *(lexeme[+(char_ - '"')]);
        start %= *(no_case[lit("fractal")] >> no_quoted_string >> '{' >> *(skip[*(char_)]) >> '}');
    }

    rule<Iterator, std::string(), space_type> no_quoted_string;
    rule<Iterator, std::vector<std::string>(), space_type> start;
};

int main() {

    const std::string fractalListFile(R"(
    fractal mand1 {
        ;lkkj;kj;
    }

    fractal mand2 {
        if (...) {
            blablah;
        }
    }

    fractal julia1 {
        a = ss;
    }
    )");

    std::cout << "Read Test:" << std::endl;
    FractalListParser<sit> parser;
    std::vector<std::string> data;
    bool r = phrase_parse(fractalListFile.begin(), fractalListFile.end(), parser, space, data);
    for (auto& i : data) std::cout << i << std::endl;
    return 0;
}

最佳答案

如果你使用错误处理,你会发现解析失败,没有任何有效的解析:

Live On Coliru

输出:

Read Test:
Parse success:
----
mand1 {
    ;lkkj;kj;
}

fractal mand2 {
    if (...) {
        blablah;
    }
}

fractal julia1 {
    a = ss;
}

Remaining unparsed input: 'fractal mand1 {
    ;lkkj;kj;
}

fractal mand2 {
    if (...) {
        blablah;
    }
}

fractal julia1 {
    a = ss;
}
'

问题是什么?

  1. 您可能想要忽略“正文”(在 {} 之间)。因此我想您实际上想要省略属性:

         >> '{' >> *(omit[*(char_)]) >> '}'
    

    而不是 skip(*char_)

  2. 表达式 *char_ 是贪婪的,并且总是匹配到输入的末尾......你可能想限制字符集:

    • 在“name”*~char_("\"{") 中也可以避免“吃掉”整个 body 。要避免匹配空格,请使用 graph(例如 +graph - '"')。如果您想明确解析“标识符”,例如

      alpha > *(alnum | char_('_'))
      
    • 在主体 *~char_('}')*(char_ - '}')(后者效率较低)。

  3. 可选量词的嵌套效率不高:

    *(omit[*(char_)])
    

    只会有非常慢的最坏情况运行时间(因为 *char_ 可能为空,而 *(omit[*(char_)]) 也可能为空) .说出你的意思:

    omit[*char_]
    
  4. 拥有词位的最简单方法是从规则声明中删除 skipper (另请参阅 Boost spirit skipper issues)

程序逻辑:

  1. 由于您的示例包含嵌套 block (例如 mand2),您需要递归地处理这些 block 以避免调用第一个 的结尾外 block :

    block = '{' >> -block % (+~char_("{}")) >> '}';
    

松散的提示:

  1. 使用 BOOST_SPIRIT_DEBUG 找出解析被拒绝/匹配的位置。例如。稍微重构规则后:

    我们得到了输出(On Coliru):

    Read Test:
    <start>
    <try>fractal mand1 {\n    </try>
    <no_quoted_string>
        <try>mand1 {\n    ;lkkj;kj</try>
        <success> {\n    ;lkkj;kj;\n}\n\n</success>
        <attributes>[[m, a, n, d, 1]]</attributes>
    </no_quoted_string>
    <body>
        <try>{\n    ;lkkj;kj;\n}\n\nf</try>
        <fail/>
    </body>
    <success>fractal mand1 {\n    </success>
    <attributes>[[]]</attributes>
    </start>
    Parse success:
    Remaining unparsed input: 'fractal mand1 {
        ;lkkj;kj;
    }
    
    fractal mand2 {
        if (...) {
            blablah;
        }
    }
    
    fractal julia1 {
        a = ss;
    }
    '
    

    该输出帮助我发现我实际上忘记了正文规则中的 - '}' 部分...:)

  2. 当规则定义中不涉及任何语义操作时,不需要 %= (docs)

  3. 您可能想确保 fractal 实际上是一个单独的词,因此您不匹配 fractalset multi { .... }


演示程序

有了这些,我们就可以有一个工作演示:

Live On Coliru

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <iostream>

namespace qi = boost::spirit::qi;

template <typename Iterator>
struct FractalListParser : qi::grammar<Iterator, std::vector<std::string>(), qi::space_type> {
    FractalListParser() : FractalListParser::base_type(start)   {
        using namespace qi;

        identifier = alpha > *(alnum | char_('_'));
        block      = '{' >> -block % +~char_("{}") >> '}';

        start      = *(
                        no_case["fractal"] >> identifier >> block
                   );

        BOOST_SPIRIT_DEBUG_NODES((start)(block)(identifier))
    }

    qi::rule<Iterator, std::vector<std::string>(), qi::space_type> start;
    // lexemes (just drop the skipper)
    qi::rule<Iterator, std::string()> identifier;
    qi::rule<Iterator> block; // leaving out the attribute means implicit `omit[]`
};

int main() {

    using It = boost::spirit::istream_iterator;
    It f(std::cin >> std::noskipws), l;

    std::cout << "Read Test:" << std::endl;

    FractalListParser<It> parser;

    std::vector<std::string> data;
    bool r = qi::phrase_parse(f, l, parser, qi::space, data);
    if (r) {
        std::cout << "Parse success:\n";
        for (auto& i : data)
            std::cout << "----\n" << i << "\n";
    } else {
        std::cout << "Parse failed\n";
    }

    if (f != l)
        std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}

打印:

Read Test:
Parse success:
----
mand1
----
mand2
----
julia1

关于c++ - 创建用于检索字符串 vector 的语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33974879/

相关文章:

c++ - 将 C 数组分配给 C+ +'s std::array? (std::array<T,U> = T[U]) - no suitable constructor exists from "T [U ]"to "std::array<T,U>"

c++ - 使用 SFML 验证实时网络上发送的数据包

c++ - 有人知道像 MFC Internals for Qt 这样的书或文档吗?

c++ - 正确对齐内存中模板,参数顺序不变

parsing - 为什么要构建 AST walker 而不是让节点负责自己的输出?

c - 使用指向数值数据的 void* 指针的算术运算

javascript - 可能的嵌套异步函数

Boost.Asio SSL 非正常关闭

c++ - 删除 .. 在 boost filesystem::complete

c++ - 创建大小为 int arr[1000000][1000000] 的大型二维数组