You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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;
}

代码说明

  1. 自定义属性处理器:VertexAttributeHandler拦截所有顶点属性赋值操作,跳过已单独绑定的label,将其他属性按键值对存入对应顶点的attributes映射。
  2. 动态属性绑定:
    • 用dp.property显式绑定顶点和边的label属性到结构体成员
    • 用dp.set_vertex_property注册自定义处理器,自动处理所有未显式声明的顶点属性
  3. 解析与验证:读取文件后遍历顶点和边,输出解析结果确认正确性。

内容的提问来源于stack exchange,提问作者Anton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 13:20:27