2012-03-27 2 views
2

PyParsing의 새로운 기능입니다. xdot 파일에서 draw (및 유사한) 특성을 구문 분석하는 방법을 알아 내려고 노력 중입니다. 다음 요소의 수는 시작 부분에 정수로 주어지며 NetString과 비슷한 종류의 항목이 있습니다. netstring과 같은 구조를 다루기 위해 샘플 코드를 살펴 봤지만 저에게는 효과가없는 것 같습니다.
P 2 811 190 815 180 806 185 :
P 3 811 190 815 180 806 185 2 점 'P', [[811, 190], [815, 180], [806, 185]]pyparsing을 사용하여 xdot 그리기 속성을 구문 분석

다각형 파싱해야합니다 (P는 다음의 점의 개수를 나타내는 후) 3 점

다각형 : 여기

일부 샘플이다 'P', [[811, 190], [815, 180]] (끝 부분에 분석되지 않은 텍스트가 있음)으로 구문 분석해야합니다.

펜 채우기 색상 후 문자 '-') 소비 :
C 4 -blue 구문 분석한다 정보 업데이트 'C', 'blue'


에 :
내가 더 맥락없이, 자신의 라인에 예제를 넣어 잘못된 생각.

S 5 -solid S 15 -setlinewidth(1) c 5 -black C 5 -black P 3 690 181 680 179 687 187 

실제 사양에 대한 http://www.graphviz.org/doc/info/output.html#d:xdot를 참조하십시오 여기에 실제 예입니다.

위의 setlinewidth (1) 텍스트 필드에 큰 공백이있을 수 있습니다. "abcd efgh hijk"일 수 있으며 정확히 15자인 경우 'S'태그와 연결해야합니다. 'P'태그 다음에 정확히 7 개의 숫자 (초기 카운터 + 3 쌍)가 있어야하며, 같은 줄에 더 많은 태그가 올 수 있기 때문에 구문 분석 오류가 발생해야합니다. 유효한.

이렇게하면 상황이 좀 더 명확 해지기를 바랍니다.

+0

을 추가, 나는 (아래) 대답을 내놓았다. 다른 견해를 듣고 더 좋은 방법이 있다면 여전히 좋아할 것입니다. 여전히 PyParsing에 만족합니다. 아래의 내 결과 (여전히 약간 '수동')는 손으로 쓰는 것보다 쓰기 (읽기)가 훨씬 쉽습니다. –

+0

그래서'P 2 811 190 815 180 806 185'는 "해석되지 않은 텍스트가 끝나기"전에 말한 것처럼 구문 분석 오류를 발생시키지 않습니까? – Hooked

+0

@Hooked : 미안 해요. 일을 간단하게하려고 노력했습니다. 그리고 나 자신을 테스트 할 때, 찾고 있던 결과를 얻는 것만으로도 구문 분석 오류에 대해 걱정하지 않아도됩니다. 그러나 'S 5 -solid P 1 690 181 680 179 C 4 -blue'는 680에서 구문 분석 오류를 실제로 발생시킵니다 (필자는 생각합니다). –

답변

1

글쎄, 결국 내가 scanString을 사용하여 생각해 냈습니다.

int_ = Word(nums).setParseAction(lambda t: int(t[0])) 
float_ = Combine(Word(nums) + Optional('.' + ZeroOrMore(Word(nums, exact=1)))).setParseAction(lambda t: float(t[0])) 
point = Group(int_ * 2).setParseAction(lambda t: tuple(t[0])) 
ellipse = ((Literal('E')^'e') + point + int_ + int_).setResultsName('ellipse') 
n_points_start = (Word('PpLBb', exact=1) + int_).setResultsName('n_points') 
text_start = ((('T' + point + int_*3)^('F' + float_ + int_)^(Word('CcS') + int_)) + '-').setResultsName('text') 
xdot_attr_parser = ellipse^n_points_start^text_start 

def parse_xdot_extended_attributes(data): 
    results = [] 
    while True: 
     try: 
      tokens, start, end = xdot_attr_parser.scanString(data, maxMatches = 1).next() 
      data = data[end:] 
      name = tokens.getName() 
      if name == 'n_points': 
       number_to_get = int(tokens[-1]) 
       points, start, end = (point * number_to_get).scanString(data, maxMatches = 1).next() 
       result = tokens[:1] 
       result.append(points[:]) 
       results.append(result) 
       data = data[end:] 
      elif name == 'text': 
       number_to_get = int(tokens[-2]) 
       text, data = data[:number_to_get], data[number_to_get:] 
       result = tokens[:-2] 
       result.append(text) 
       results.append(result) 
      else: 
       results.append(tokens) 
     except StopIteration: 
      break 
    return results 
1

영업 이익의 편집에 대응하여, 아래의 대답은 더 이상 완료되지 않습니다.

여기에서 질문의 핵심에 도달하고 세부 정보는 무시합니다. 다행히도 그것은 당신을 당신의 문법의 나머지 부분에 올바른 길로 인도 할 것입니다.

P 3 811 190 815 180 806 185 
P 2 811 190 815 180 806 185 

가 어떻게 데이터를 분석 할 수있는 두 번째 줄에 두 점을 읽을되도록 : 기본적으로 당신은 두 줄 주어진 요구하고있다? 개인적으로, 나는 모두의 데이터와 사후 파싱을 읽을 것입니다. 의 결과에이라는 이름을 붙이면 일을 훨씬 쉽게 할 수 있습니다. 예를 들어 우리가 data, flaglength 이름이

from pyparsing import * 

EOL = LineEnd().suppress() 

number = Word(nums).setParseAction(lambda x: int(x[0])) 
point_pair = Group(number + number) 

poly_flag = Group(Literal("P") + number("length"))("flag") 
poly_type = poly_flag + Group(OneOrMore(point_pair))("data") 

xdot_line = Group(poly_type) + EOL 
grammar = OneOrMore(xdot_line) 

참고이 나중에 유용합니다.의 구문 분석하자 문자열 처리 :

S = "P 3 811 190 815 180 806 185\nP 2 811 190 815 180 806 185\n" 
P = grammar.parseString(S) 

for line in P: 
    L = line["flag"]["length"] 
    while len(line["data"]) > L: 
     line["data"].pop() 

유용한 구조화 된 결과주기 : 독립적 문법의 조각을 구축 할 수 있습니다, 여기에서

문법을 확장

[['P', 3], [[811, 190], [815, 180], [806, 185]]] 
[['P', 2], [[811, 190], [815, 180]]] 

을 하나의 별 -하나. 새 유형을 추가 할 때마다, 좀 더 생각 후, xdot_line에 즉

xdot_line = Group(poly_type | pen_fill_type) + EOL 

+0

+1 결과 이름 사용. 필자는 개인적으로 dict 표기법에 비해 점으로 구분 된 속성 표기법을 선호하므로''line.flag.length''와''line.data''를 쓸 수 있습니다. – PaulMcG

+0

@PaulMcGuire 두 경우 모두 용도가 있다고 생각합니다.이 경우 점으로 구분 된 표기법이 더 깔끔할 수 있지만 함수 호출에서 결과 이름을 전달하여 표기법을 유용하게 사용합니다. – Hooked

+0

@PaulMcGuire는 모든 일에''pyparsing'에 대한 전문가입니다.이 사이트에서 제공 한 모든 도움에 감사드립니다! OP가 원하는 것처럼, 다음 n 문자 (공백 포함)를 소비하는 방법이 있는지 알고 싶습니다. 여기서 n은 이전 토큰에서 읽습니다. – Hooked

관련 문제