Replace lit with different string in boost spirit

江枫思渺然 提交于 2021-01-28 05:13:37

问题


I'm trying to parse a quoted string containing escape sequences using boost spirit. I'm looking for a way to replace escape sequences \" with the corresponding character (" in this case). So far I've come up with this.

c_string %= lit('"') >> *(lit("\\\"")[push_back(_val, '"')] | (char_ - '"')) >> lit('"')

with the replacement being done with

lit("\\\"")[push_back(_val, '"')]

however this seems to me quite clumsy and unreadable. Is there a better way to accomplish this?


回答1:


Iterating: you can replace "\\\"" with '\\' >> lit('"'), reformatting a bit:

c_string
    %= lit('"')
    >> *(
           '\\' >> lit('"')[push_back(_val, '"')]
         | (char_ - '"')
    )
    >> lit('"')
    ;

Now, you can do away with some of the lit() calls because they're implicit when invoking proto expressions in the Qi domain:

c_string
    %= '"'
    >> *(
           '\\' >> lit('"')[push_back(_val, '"')]
         | (char_ - '"')
    )
    >> '"'
    ;

Next up, lit(ch)[push_back(_val, ch)] is just a clumsy way to say char_(ch):

c_string = '"'
    >> *( '\\' >> char_('"') | (char_ - '"') )
    >> '"';

Note now we don't have the kludge of %= either (see Boost Spirit: "Semantic actions are evil"?) and you can leave the phoenix.hpp include(s)

Finally, you can have a more optimized char_ - char_(xyz) by saying ~char_(xyz):

c_string = '"' >> *('\\' >> char_('"') | ~char_('"')) >> '"';

Now, you're not actually parsing C-style strings here. You're not handling escapes, so why not simplify:

c_string = '"' >> *('\\' >> char_|~char_('"')) >> '"';

Note that now you actually parse backslash escapes, which you would otherwise not (you would parse "\\" into "\\" instead of "\")

If you want to be more precise, consider handling escapes like e.g. Handling utf-8 in Boost.Spirit with utf-32 parser

Live Demo

Live On Coliru

#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

int main() {
    const qi::rule<std::string::const_iterator, std::string()> c_string
        = '"' >> *('\\' >> qi::char_|~qi::char_('"')) >> '"';

    for (std::string const input: {
            R"("")"               , // ""
            R"("\"")"             , // "\\\""
            R"("Hello \"world\"")", // "Hello \\\"world\\\""
        })
    {
        std::string output;
        if (parse(input.begin(), input.end(), c_string, output)) {
            std::cout << input << " -> " << output << "\n";
        } else {
            std::cout << "Failed: " << input << "\n";
        }
    }
}

Prints

"" -> 
"\"" -> "
"Hello \"world\"" -> Hello "world"


来源:https://stackoverflow.com/questions/60450190/replace-lit-with-different-string-in-boost-spirit

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!