Замените горит другой струной в буст-спирит - PullRequest
1 голос
/ 28 февраля 2020

Я пытаюсь разобрать строку в кавычках, содержащую escape-последовательности, с использованием Boost Spirit. Я ищу способ заменить escape-последовательности \" на соответствующий символ (" в данном случае). До сих пор я придумал это.

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

с заменой, сделанной с

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

, но, похоже, это я довольно неуклюжий и нечитаемый Есть ли лучший способ выполнить это? 1014 *?

1 Ответ

1 голос
/ 28 февраля 2020

Итерация: вы можете заменить "\\\"" на '\\' >> lit('"'), переформатируя немного:

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

Теперь вы можете покончить с некоторыми вызовами lit(), потому что они неявны при вызове прото-выражения в домене Qi:

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

Далее, lit(ch)[push_back(_val, ch)] - это просто неуклюжий способ сказать char_(ch):

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

Заметьте, теперь мы не у него также может быть %= (см. Повышение духа: «Семанти c действия злые»? ), и вы можете оставить phoenix.hpp include (s)

Наконец, вы можете получить более оптимизированный char_ - char_(xyz), сказав ~char_(xyz):

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

Теперь вы на самом деле здесь не разбираете строки C. Вы не обрабатываете экранирование, так почему бы не упростить:

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

Обратите внимание, что теперь вы фактически анализируете экскаваторы backsla sh, что в противном случае вы не сделали бы (вы бы проанализировали "\\" в "\\" вместо "\")

Если вы хотите быть более точным, рассмотрите возможность обработки экранированных символов, например, Обработка utf-8 в Boost.Spirit с анализатором utf-32

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";
        }
    }
}

Печать

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