Python 使用curley brakets解析文件

Python 使用curley brakets解析文件,python,parsing,pyparsing,Python,Parsing,Pyparsing,我需要解析一个文件,其中的信息用花括号隔开,例如: Continent { Name Europe Country { Name UK Dog { Name Fiffi Colour Gray } Dog { Name Smut Colour Black } } } 下面是我在Python中尝试的内容 from io import open from pyparsing import * import pprint def parse(s): return

我需要解析一个文件,其中的信息用花括号隔开,例如:

Continent
{
Name    Europe
Country
{
Name    UK
Dog
{
Name    Fiffi
Colour  Gray
}
Dog
{
Name    Smut
Colour  Black
}
}
}
下面是我在Python中尝试的内容

from io import open
from pyparsing import *
import pprint

def parse(s):
    return nestedExpr('{','}').parseString(s).asList()

def test(strng):
    print strng
    try:
        cfgFile = file(strng)
        cfgData = "".join( cfgFile.readlines() )
        list = parse( cfgData )
        pp = pprint.PrettyPrinter(2)
        pp.pprint(list)

    except ParseException, err:
        print err.line
        print " "*(err.column-1) + "^"
        print err

    cfgFile.close()
    print
    return list

if __name__ == '__main__':
    test('testfile')
但这失败了,出现了一个错误:

testfile
Continent
^
Expected "{" (at char 0), (line:1, col:1)

Traceback (most recent call last):
  File "xxx.py", line 55, in <module>
    test('testfile')
  File "xxx.py", line 40, in test
    return list
UnboundLocalError: local variable 'list' referenced before assignment  
testfile
大陆
^
应为“{”(字符0处),(行:1,列:1)
回溯(最近一次呼叫最后一次):
文件“xxx.py”,第55行,在
测试('testfile')
文件“xxx.py”,第40行,在测试中
返回列表
UnboundLocalError:赋值前引用的局部变量“list”
我需要做些什么才能让它工作? 还有比pyparsing更好的解析器吗?

递归性是这里的关键。尝试以下方法:

def parse(it):
    result = []
    while True:
        try:
            tk = next(it)
        except StopIteration:
            break

        if tk == '}':
            break
        val = next(it)
        if val == '{':
            result.append((tk,parse(it)))
        else:
            result.append((tk, val))

    return result
用例:

import pprint       

data = """
Continent
{
Name    Europe
Country
{
Name    UK
Dog
{
Name    Fiffi
Colour  Gray
}
Dog
{
Name    Smut
Colour  Black
}
}
}
"""

r = parse(iter(data.split()))
pprint.pprint(r)
…它们产生(Python 2.6):

请将此作为唯一的出发点,并根据需要随时改进代码(根据您的数据,字典可能是更好的选择)。此外,示例代码不能正确处理格式错误的数据(特别是额外的或缺少的
}
——我敦促您进行全面测试;)


编辑:发现
pyparsing
,我尝试了以下方法,似乎效果更好,可以(更)方便地针对特殊需求进行定制:

import pprint
from pyparsing import Word, Literal, Forward, Group, ZeroOrMore, alphas

def syntax():
    lbr = Literal( '{' ).suppress()
    rbr = Literal( '}' ).suppress()
    key = Word( alphas )
    atom = Word ( alphas )
    expr = Forward()
    pair = atom | (lbr + ZeroOrMore( expr ) + rbr)
    expr << Group ( key + pair )

    return expr

expr = syntax()
result = expr.parseString(data).asList()
pprint.pprint(result)

嵌套表达式非常常见,如果不使用解析库,通常需要递归解析器定义或递归代码。这段代码对于初学者来说可能会让人望而生畏,甚至对于专家来说也很容易出错,所以我在pyparsing中添加了
nestedExpr
helper

您遇到的问题是,您的输入字符串中不仅仅包含嵌套的大括号表达式。当我第一次尝试一个解析器时,我会尽量保持测试的简单性——例如,我内联样本,而不是从文件中读取样本

test = """\
Continent
{
Name    Europe
Country
{
Name    UK
Dog
{
Name    Fiffi
Colour  "light Gray"
}
Dog
{
Name    Smut
Colour  Black
}}}"""

from pyparsing import *

expr = nestedExpr('{','}')

print expr.parseString(test).asList()
我得到了与您相同的解析错误:

Traceback (most recent call last):
  File "nb.py", line 25, in <module>
    print expr.parseString(test).asList()
  File "c:\python26\lib\site-packages\pyparsing-1.5.7-py2.6.egg\pyparsing.py", line 1006, in parseString
    raise exc
pyparsing.ParseException: Expected "{" (at char 1), (line:1, col:1)
现在,将结果打印为列表(在OP中使用pprint,做得很好)如下所示:

['Continent',
 ['Name',
  'Europe',
  'Country',
  ['Name',
   'UK',
   'Dog',
   ['Name', 'Fiffi', 'Colour', '"light Gray"'],
   'Dog',
   ['Name', 'Smut', 'Colour', 'Black']]]]

这应该与大括号嵌套匹配。

主题外,但最好不要使用
列表
作为变量名,因为它在pythonI中是保留的。我可以使用基于递归的算法为您提出解决方案。它是否符合您的要求(一次按“{”分割整个数据,一次按“}”分割rsplit。外部部分应作为返回字典的键值进行解析,内部部分应传递给递归函数本身。等等…)请说明结果如何。为什么要否决该问题?它可能需要一些额外的信息,如预期输出。。。但是有趣的是???使用
split()
来分解标记对这个示例数据有效,但并非所有的输入都可以很好地格式化<例如,如果后面的大括号被输入为“}}}”,或者如果任何条目在带引号的字符串中包含大括号,则代码>拆分()将失败。@PaulMcGuire这是正确的。最初的问题并没有完全指定输入数据的格式。关于花括号周围的空格——一个regexp就可以了。如果语法更复杂,例如,如您所说,包含带引号的stings--
pyparsing
仍然是一个更好的选择。做得好,这是一个比仅使用nestedExpr更严格的解析器,您保留了键+值关系。欢迎来到这里,西尔文!多亏了这个问题,我发现了pyparsing——虽然网上没有太多文档,但确实是一个非常有趣的模块。有没有办法生成字典而不是嵌套列表?
Traceback (most recent call last):
  File "nb.py", line 25, in <module>
    print expr.parseString(test).asList()
  File "c:\python26\lib\site-packages\pyparsing-1.5.7-py2.6.egg\pyparsing.py", line 1006, in parseString
    raise exc
pyparsing.ParseException: Expected "{" (at char 1), (line:1, col:1)
expr = Word(alphas) + nestedExpr('{','}')
['Continent',
 ['Name',
  'Europe',
  'Country',
  ['Name',
   'UK',
   'Dog',
   ['Name', 'Fiffi', 'Colour', '"light Gray"'],
   'Dog',
   ['Name', 'Smut', 'Colour', 'Black']]]]