2013-10-15 2 views
0

나는 다음과 같은 텍스트 청크가 : 나는 나를 키 값을 구문 분석 할 수있는 좋은 정규식을 찾기 위해 노력하고구문 분석 콜론으로 구분 된 데이터

string = """ 
    apples: 20 
    oranges: 30 
    ripe: yes 
    farmers: 
      elmer fudd 
        lives in tv 
      farmer ted 
        lives close 
      farmer bill 
        lives far 
    selling: yes 
    veggies: 
      carrots 
      potatoes 
    """ 

합니다. 다음과 같이 한 줄 키 값을 가져올 수 있습니다.

'(.+?):\s(.+?)\n' 

그러나 내가 농부 나 채식주의자를 때리면 문제가 발생합니다. 나는 농부와 관련된 모든 값을 잡는 시간의 지옥을 데, 그러나

re.findall('(.+?):\s(.+?)\n', string, re.S), 

: 재 플래그를 사용

, 내가 좋아하는 뭔가를 할 필요가있다.

각 값 다음에 줄 바꿈이 있고 여러 줄인 경우 값 앞에 탭 또는 일련의 탭이 있습니다.

{ 'apples': 20, 'farmers': ['elmer fudd', 'farmer ted'] } 

당신의 도움에 미리 감사합니다

과 목표는 같은 일을하는 것입니다.

+0

'lives in tv'부분이 중요합니까? 원하는 출력으로 언급하지 않았습니다. –

+0

이 접근법은 어떻습니까? 줄 바꿈에 의한 분할은'x'로 저장하고 각 줄을 단계별로 실행하고': ''로 분할하십시오. 두 번째 부분이 비어 있지 않으면 두 쌍을 키와 값으로 사전에 추가하고'x'에서 줄을 띄웁니다. 그 다음에는 '(:'포함) 키 목록 만 남게되고 나머지는 그 키 목록에 들어갑니다. 트리밍 된'x'를 실행하고 나머지를 사전에 추가하십시오. –

+0

''tv에 사는''이 목록에 나오지 않는 이유는 무엇입니까? 또는 "농부 법안"이라고할까요? – abarnert

답변

1

여기 (명백한) 들여 쓰기 규칙을 고려 정말 바보 파서입니다 :

def parse(s): 
    d = {} 
    lastkey = None 
    for fullline in s: 
     line = fullline.strip() 
     if not line: 
      pass 
     elif ':' not in line: 
      indent = len(fullline) - len(fullline.lstrip()) 
      if lastindent is None: 
       lastindent = indent 
      if lastindent == indent: 
       lastval.append(line) 
     else: 
      if lastkey: 
       d[lastkey] = lastval 
       lastkey = None 
      if line.endswith(':'): 
       lastkey, lastval, lastindent = key, [], None 
      else: 
       key, _, value = line.partition(':') 
       d[key] = value.strip() 
    if lastkey: 
     d[lastkey] = lastval 
     lastkey = None 
    return d 

import pprint 
pprint(parse(string.splitlines())) 

출력은 다음과 같습니다.

{'apples': '20', 
'oranges': '30', 
'ripe': ['elmer fudd', 'farmer ted', 'farmer bill'], 
'selling': ['carrots', 'potatoes']} 

이것은 이미 명백한 상태 머신으로 더 깨끗해 보일 정도로 복잡하다고 생각하지만 모든 초보자가 이해할 수있는 용어로 이것을 작성하려고했습니다.

+0

감사합니다.이 솔루션은 매우 깨끗합니다. 나는 처음에이를 정규 표현식으로 해결하려고했지만 정규 표현식은 그만한 가치가 없으며 더 복잡한 결과를 가져올 수 있습니다. – user2152283

+0

@ user2152283 : 정규 표현식으로 무엇인가를 수행하는 방법을 알아낼 수 없을 때마다 (구문 분석하려고하는 정규 언어라고하더라도), 나는 뒤로 물러나 다른 방식으로 작성하려고합니다. 때로는 정규 표현식을 무의식적으로 파악할 수 있습니다. 때로는 정규 표현식이 아닌 읽을 수있는 파서로 끝나는 것을 의미합니다. 때로는 언어가 비정규 적이거나 심지어 문맥에 민감하다는 것을 스스로 증명하는 결과를 낳기도하고 더 복잡한 것을 필요로 할 것입니다. 그러나 무엇을하더라도 그것이 승리입니다. – abarnert

2

PyYAML에서 볼 수 있습니다.이 텍스트는 실제로 유효하지 않지만 YAML과 매우 비슷합니다.

+0

가깝지만, 나는'농부들 '이 하나의 긴 문자열로 끝날 것이라고 믿습니다. 이것은 꽤 목록이 아닙니다. –

+0

또는 잠재적으로 구문 분석 오류가 발생합니다. –

+0

값을 가져올 수 있으면 줄 바꿈으로 분할하고 목록을 구성 할 수 있습니다. 그러나, 가치를 잡는 최선의 방법을 찾으려 고 노력했습니다. – user2152283

1

여기에 그것을 할 수있는 완전히 어리석은 방법 :

import collections 


string = """ 
    apples: 20 
    oranges: 30 
    ripe: yes 
    farmers: 
      elmer fudd 
        lives in tv 
      farmer ted 
        lives close 
      farmer bill 
        lives far 
    selling: yes 
    veggies: 
      carrots 
      potatoes 
    """ 


def funky_parse(inval): 
    lines = inval.split("\n") 
    items = collections.defaultdict(list) 
    at_val = False 
    key = '' 
    val = '' 
    last_indent = 0 
    for j, line in enumerate(lines): 
     indent = len(line) - len(line.lstrip()) 
     if j != 0 and at_val and indent > last_indent > 4: 
      continue 
     if j != 0 and ":" in line: 
      if val: 
       items[key].append(val.strip()) 
      at_val = False 
      key = '' 
     line = line.lstrip() 
     for i, c in enumerate(line, 1): 
      if at_val: 
       val += c 
      else: 
       key += c 
      if c == ':': 
       at_val = True 
      if i == len(line) and at_val and val: 
       items[key].append(val.strip()) 
       val = '' 
     last_indent = indent 

    return items 

print dict(funky_parse(string)) 

OUTPUT

{'farmers:': ['elmer fudd', 'farmer ted', 'farmer bill'], 'apples:': ['20'], 'veggies:': ['carrots', 'potatoes'], 'ripe:': ['yes'], 'oranges:': ['30'], 'selling:': ['yes']} 
+0

감사합니다.이 솔루션도 잘 작동합니다. – user2152283

관련 문제