Python将C头文件转换为字典

2 投票
1 回答
2808 浏览
提问于 2025-04-18 15:16

我有一个C语言的头文件,里面包含了一系列的类。我想写一个函数,把这些类转换成Python的字典。下面是这个文件的一个示例。

格式大概是这样的:

class CFGFunctions {
  class ABC {
    class AA {
      file = "abc/aa/functions"
      class myFuncName{ recompile = 1; };
    };
    class BB
    {
      file = "abc/bb/functions"
      class funcName{
        recompile=1;
      }
    }
  };
};

我希望能把它变成这样:

{CFGFunctions:{ABC:{AA:"myFuncName"}, BB:...}}
# Or
{CFGFunctions:{ABC:{AA:{myFuncName:"string or list or something"}, BB:...}}}

最后,我想得到一个文件路径字符串(其实是一个文件夹的路径……不过无所谓),还有与这个文件/文件夹路径在同一个类里的类名。

我在StackOverflow和谷歌上查过,但大多数找到的内容都是关于把行分割成字典,而不是处理多层的“块”。

我知道我需要遍历这个文件,但我不太确定最有效的方式来转换成字典。我在想,我需要抓取外层的类和它相关的括号,然后对里面剩下的文本做同样的处理。

如果这些说的不太清楚,那是因为我自己也还没完全搞明白这个过程,哈哈。

如果需要更多信息,我很乐意提供。

下面的代码是我大概想的一个快速示例……它很可能是坏的,也可能不工作,但这就是我想到的过程。

def get_data():
    fh = open('CFGFunctions.h', 'r')
    data = {}    # will contain final data model

    # would probably refactor some of this into a function to allow better looping
    start = ""   # starting class name
    brackets = 0 # number of brackets
    text= ""     # temp storage for lines inside block while looping
    for line in fh:
        # find the class (start
        mt = re.match(r'Class ([\w_]+) {', line)
        if mt:
            if start == "":
                start = mt.group(1)
            else:
                # once we have the first class, find all other open brackets
                mt = re.match(r'{', line)
                if mt:
                    # and inc our counter
                    brackets += 1
                mt2 = re.match(r'}', line)
                if mt2:
                    # find the close, and decrement
                    brackets -= 1
                    # if we are back to the initial block, break out of the loop
                    if brackets == 0:
                        break
                text += line
    data[start] = {'tempText': text}

====

示例文件

class CfgFunctions {
    class ABC {
        class Control {
            file = "abc\abc_sys_1\Modules\functions";
            class assignTracker {
                description = "";
                recompile = 1;
            };

            class modulePlaceMarker {
                description = "";
                recompile = 1;
            };
        };

        class Devices
        {
            file = "abc\abc_sys_1\devices\functions";
            class registerDevice { recompile = 1; };
            class getDeviceSettings { recompile = 1; };
            class openDevice { recompile = 1; };
        };
    };
};

编辑:如果可能的话,如果我必须使用一个包,我希望它在程序的目录下,而不是在一般的Python库目录下。

1 个回答

2

正如你所发现的,解析是进行转换所必需的。可以看看PyParsing这个库,它是一个相对简单易用的库,可以在你的Python程序中实现解析。

补充说明:这只是一个非常简化的版本,用来识别一个非常简单的语法,类似于问题开头的例子。虽然这个代码不能直接工作,但可能会给你指明方向:

from pyparsing import ZeroOrMore, OneOrMore, \
                      Keyword, Literal


test_code = """
class CFGFunctions {
  class ABC {
    class AA {
      file = "abc/aa/functions"
      class myFuncName{ recompile = 1; };
    };
    class BB
    {
      file = "abc/bb/functions"
      class funcName{
        recompile=1;
      }
    }
  };
};
"""

class_tkn       = Keyword('class')
lbrace_tkn      = Literal('{')
rbrace_tkn      = Literal('}')
semicolon_tkn   = Keyword(';')
assign_tkn      = Keyword(';')

class_block     = ( class_tkn + identifier + lbrace_tkn + \
                    OneOrMore(class_block | ZeroOrMore(assignment)) + \
                    rbrace_tkn + semicolon_tkn \
                  )

def test_parser(test):
    try:
        results = class_block.parseString(test)
        print test, ' -> ', results
    except ParseException, s:
        print "Syntax error:", s


def main():
    test_parser(test_code)

    return 0

if __name__ == '__main__':
    main()

另外,这段代码只是解析器 - 它并不会生成任何输出。正如你在PyParsing的文档中看到的,你可以在后面添加你想要的操作。但第一步是识别你想要翻译的内容。

最后一点:不要低估解析代码的复杂性……即使有像PyParsing这样的库来处理大部分工作,仍然有很多方法可能让你陷入无限循环和其他解析的麻烦中。要一步一步地实现功能!

补充:关于PyParsing的一些信息来源有:

http://werc.engr.uaf.edu/~ken/doc/python-pyparsing/HowToUsePyparsing.html

http://pyparsing.wikispaces.com/

特别有趣的是http://pyparsing.wikispaces.com/Publications,里面有很多文章 - 其中有几篇是关于PyParsing的入门介绍。

http://pypi.python.org/pypi/pyparsing_helper是一个用于调试解析器的图形界面工具。

在stackoverflow上还有一个'Pyparsing'标签,PyParsing的作者Paul McGuire似乎经常在那儿出现。

* 注意: *来自PaulMcG的评论:Pyparsing不再托管在wikispaces.com上。请访问github.com/pyparsing/pyparsing

撰写回答