Итерация: вы можете заменить "\\\""
на '\\' >> 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"