如何用Boost Graph Library的read_graphviz解析自定义属性顶点
解析Graphviz文件并适配Boost Graph Library的捆绑属性结构体
问题说明
需要解析如下格式的Graphviz文件:
0[label="person" name="James Cameron"]; 1[label="film" title="Avatar 2" year="2022"]; 0->1 [label="directed"]; }``` 核心要求: - 顶点必须包含`label`属性,同时支持数量未知、结构可变的自定义属性 - 边仅需处理`label`属性 - 使用Boost Graph Library的`read_graphviz`函数完成解析,避免手写解析器,适配以下Vertex结构体: ```cpp struct Vertex { std::string label; std::map<std::string, std::string> attributes; };
解决方案
实现思路
利用Boost的dynamic_properties机制,结合自定义属性处理器,将顶点除label外的所有属性自动存入attributes映射,无需修改原始Graphviz格式。
完整代码示例
#include <iostream> #include <fstream> #include <vector> #include <map> #include <string> #include <cstdlib> #include <boost/graph/graphviz.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/property_map/dynamic_property_map.hpp> struct Vertex { std::string label; std::map<std::string, std::string> attributes; }; struct Edge { std::string label; }; typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge> Graph; // 自定义顶点属性处理器,处理非label的动态属性 class VertexAttributeHandler { public: typedef std::string key_type; typedef std::string value_type; typedef value_type reference; VertexAttributeHandler(Graph& graph) : m_graph(graph) {} void operator()(const key_type& vertex_id, const key_type& attr_name, const value_type& attr_value) { // 跳过已单独绑定的label属性 if (attr_name == "label") return; // 将顶点ID转为索引,存入对应顶点的属性映射 size_t idx = std::stoul(vertex_id); m_graph[idx].attributes[attr_name] = attr_value; } private: Graph& m_graph; }; int main(int argc, char** argv) { if (argc != 2) { std::cerr << "使用方式: " << argv[0] << " <graphviz文件路径>" << std::endl; return EXIT_FAILURE; } Graph graph; boost::dynamic_properties dp(boost::ignore_other_properties); // 绑定顶点的label属性到结构体成员 dp.property("label", boost::get(&Vertex::label, graph)); // 绑定边的label属性到结构体成员 dp.property("label", boost::get(&Edge::label, graph)); // 注册自定义处理器,处理所有未显式绑定的顶点属性 VertexAttributeHandler attr_handler(graph); dp.set_vertex_property(attr_handler); std::ifstream input_file(argv[1]); if (!input_file.is_open()) { std::cerr << "无法打开文件: " << argv[1] << std::endl; return EXIT_FAILURE; } // 解析Graphviz文件 boost::read_graphviz(input_file, graph, dp); // 输出解析结果验证 std::cout << "解析得到的顶点:" << std::endl; for (size_t i = 0; i < boost::num_vertices(graph); ++i) { const Vertex& v = graph[i]; std::cout << "顶点 " << i << ": label=" << v.label << std::endl; for (const auto& attr : v.attributes) { std::cout << " " << attr.first << " = " << attr.second << std::endl; } } std::cout << "\n解析得到的边:" << std::endl; for (auto e : boost::make_iterator_range(boost::edges(graph))) { const Edge& edge = graph[e]; std::cout << boost::source(e, graph) << " -> " << boost::target(e, graph) << ": label=" << edge.label << std::endl; } return EXIT_SUCCESS; }
代码说明
- 自定义属性处理器:
VertexAttributeHandler拦截所有顶点属性赋值操作,跳过已单独绑定的label,将其他属性按键值对存入对应顶点的attributes映射。 - 动态属性绑定:
- 用
dp.property显式绑定顶点和边的label属性到结构体成员 - 用
dp.set_vertex_property注册自定义处理器,自动处理所有未显式声明的顶点属性
- 用
- 解析与验证:读取文件后遍历顶点和边,输出解析结果确认正确性。
内容的提问来源于stack exchange,提问作者Anton
相关产品推荐
相关产品推荐

