为何boost::spirit::qi规则无法解析PureData画布字符串?
PureData画布记录解析问题:Boost Spirit规则修正
问题分析
你遇到的解析失败核心原因是字符串规则的匹配范围错误:默认的字符匹配规则会过度匹配后续的整数和分号,导致后续规则无法匹配;或者未正确处理空白跳过逻辑,导致字符串解析与skipper冲突。
常见错误规则示例
如果你的原始规则类似这样,必然会失败:
// 错误示例:qi::+qi::char_会匹配包括"1;"在内的所有后续字符 qi::rule<It, Canvas(), qi::space_type> canvas_rule = "#N canvas" >> qi::int_ >> qi::int_ >> qi::int_ >> qi::int_ >> qi::+qi::char_ >> qi::int_ >> ';';
修正后的解析规则
基础版本(名称不含空白)
针对你提供的moo这类无空白的名称,定义精确匹配非空白、非分号字符的规则:
#include <boost/spirit/include/qi.hpp> #include <string> namespace qi = boost::spirit::qi; // 画布数据结构 struct Canvas { int x, y, width, height; std::string name; int flag; }; template <typename Iterator> struct CanvasGrammar : qi::grammar<Iterator, Canvas(), qi::space_type> { CanvasGrammar() : CanvasGrammar::base_type(canvas_rule) { // 匹配不含空白和分号的字符串,用lexeme禁用内部空白跳过 name_rule = qi::lexeme[+(qi::char_ - qi::space - ';')]; canvas_rule = "#N canvas" >> qi::int_ >> qi::int_ >> qi::int_ >> qi::int_ // 解析四个坐标/尺寸整数 >> name_rule // 解析画布名称 >> qi::int_ // 解析末尾标志位 >> ';'; // 匹配终止分号 } qi::rule<Iterator, std::string(), qi::space_type> name_rule; qi::rule<Iterator, Canvas(), qi::space_type> canvas_rule; }; // 测试代码 int main() { const std::string input = "#N canvas 0 0 400 300 moo 1;"; auto iter = input.begin(); auto end_iter = input.end(); CanvasGrammar<decltype(iter)> parser; Canvas canvas_data; bool success = qi::phrase_parse(iter, end_iter, parser, qi::space, canvas_data); if (success && iter == end_iter) { // 解析成功,可使用canvas_data } return 0; }
进阶版本(支持带引号的空白名称)
如果PureData画布名称包含空白(会用双引号包裹),可以扩展名称规则:
name_rule = qi::lexeme[ '"' >> *(qi::char_ - '"') >> '"' // 匹配带双引号的字符串 | +(qi::char_ - qi::space - ';') // 兼容无空白的名称 ];
关键修正点
- 使用
qi::lexeme:确保解析字符串时禁用全局空白skipper,避免字符串内部的空白被错误跳过。 - 精确限制字符串匹配范围:通过
qi::char_ - qi::space - ';'明确字符串只匹配到下一个空白或分号前的字符,不会过度匹配后续内容。 - 规则顺序与结构对齐:严格对应
#N canvas <int> <int> <int> <int> <string> <int>;的格式顺序,确保每个字段规则正确对应。
内容的提问来源于stack exchange,提问作者stix
相关产品推荐
相关产品推荐

