2011-03-07 4 views
5

일부 특수 데이터 구조를 구문 분석해야합니다. 그들은이 같은 약 보이는 일부 약간 같은-C 형식으로되어 있습니다 :코드를 파싱하는 법 (파이썬에서)?

Group("GroupName") { 
    /* C-Style comment */ 
    Group("AnotherGroupName") { 
     Entry("some","variables",0,3.141); 
     Entry("other","variables",1,2.718); 
    } 
    Entry("linebreaks", 
      "allowed", 
      3, 
      1.414 
     ); 
} 

내가 이것에 대해 갈 수있는 몇 가지 방법을 생각할 수있다. 정규식을 사용하여 코드를 '토큰 화'할 수있었습니다. 한 번에 한 문자 씩 코드를 읽고 상태 시스템을 사용하여 데이터 구조를 구성 할 수있었습니다. 나는 쉼표 줄 바꿈을 없애고 그 줄을 한 줄씩 읽을 수있었습니다. 이 코드를 실행 가능한 Python 코드로 변환하는 변환 스크립트를 작성할 수 있습니다.

이와 같은 파일을 구문 분석 할 수있는 좋은 파이썬 방법이 있습니까?
파싱에 대해 어떻게 생각하십니까?

이것은 특정 파일 형식에 관한 것이 아니라 문자열을 구문 분석하는 방법에 대한 일반적인 질문입니다.

+3

[이 기사] (http://nedbatchelder.com/text/python-parsers.html)가 관심의 대상 일 수 있습니다. –

답변

6

(마크 Tolonen, 나는 클릭 게시물을 통해 올 때 "후 제출"그냥하고 있었다), 이것은 매우 간단합니다 - 아래의 코드에 포함 된 주석을 참조하십시오

data = """Group("GroupName") { 
    /* C-Style comment */ 
    Group("AnotherGroupName") { 
     Entry("some","variables",0,3.141); 
     Entry("other","variables",1,2.718); 
    } 
    Entry("linebreaks", 
      "allowed", 
      3, 
      1.414 
     ); 
} """ 

from pyparsing import * 

# define basic punctuation and data types 
LBRACE,RBRACE,LPAREN,RPAREN,SEMI = map(Suppress,"{}();") 
GROUP = Keyword("Group") 
ENTRY = Keyword("Entry") 

# use parse actions to do parse-time conversion of values 
real = Regex(r"[+-]?\d+\.\d*").setParseAction(lambda t:float(t[0])) 
integer = Regex(r"[+-]?\d+").setParseAction(lambda t:int(t[0])) 

# parses a string enclosed in quotes, but strips off the quotes at parse time 
string = QuotedString('"') 

# define structure expressions 
value = string | real | integer 
entry = Group(ENTRY + LPAREN + Group(Optional(delimitedList(value)))) + RPAREN + SEMI 

# since Groups can contain Groups, need to use a Forward to define recursive expression 
group = Forward() 
group << Group(GROUP + LPAREN + string("name") + RPAREN + 
      LBRACE + Group(ZeroOrMore(group | entry))("body") + RBRACE) 

# ignore C style comments wherever they occur 
group.ignore(cStyleComment) 

# parse the sample text 
result = group.parseString(data) 

# print out the tokens as a nice indented list using pprint 
from pprint import pprint 
pprint(result.asList()) 

인쇄를

대한 파싱은 구문 분석 토큰에 구조를 부여 들어, "그룹"클래스를 정의하기 때문에
[['Group', 
    'GroupName', 
    [['Group', 
    'AnotherGroupName', 
    [['Entry', ['some', 'variables', 0, 3.141]], 
    ['Entry', ['other', 'variables', 1, 2.718]]]], 
    ['Entry', ['linebreaks', 'allowed', 3, 1.4139999999999999]]]]] 

이 (불행히도, 약간의 혼동이있을 수 있습니다 - 목록식이 대한 파싱 그룹 내에 포함되는 때문에 항목의 값 목록을 그룹화되는 방법을주의 .)

+3

O'Reilly 서점에서 방금 $ 10을 받았습니다! – bastibe

1

얼마나 자주 필요하며 구문이 동일하게 유지되는지 여부에 따라 다릅니다. 대답이 "꽤 자주" "많거나 적다"면 구문을 표현하고 PyPEG 또는 LEPL과 같은 도구를 사용하여 특정 구문 분석기를 해당 언어로 작성하는 방법을 살펴볼 것입니다. 파서 규칙을 정의하는 것은 큰 일이므로 같은 종류의 파일을 자주 분석해야만 그렇지 않으면 반드시 효과적 일 수는 없습니다.

그러나 PyPEG 페이지를 보면 XML로 구문 분석 된 데이터를 출력하는 방법을 알려주므로 도구로 충분하지 않으면 XML을 생성 한 다음 예를 들어 사용할 수 있습니다. lxml은 XML을 구문 분석합니다.

관련 문제