2013-08-27 4 views
4

오케이, 마침내 내 모든 테스트 사례를 캡처하는 문법을 얻었지만 복제본 (사례 3)과 오 탐지 (사례 6, "패턴 5")가 있습니다. 내 test cases과 내 desired output입니다.pyparsing에서 중복을 생략하는 방법은 무엇입니까?

나는 아직 파이썬에 꽤 새로운데 (비록 내 아이들을 가르 칠 수 있지만 무서운거야!) 그래서이 문제를 해결할 명백한 방법이 있다고 확신한다. 여기 내 출력이 지금의 모습입니다 :

['01/01/01','S01-12345','20/111-22-1001',['GLEASON', ['5', '+', '4'], '=', '9']] 
['02/02/02','S02-1234','20/111-22-1002',['GLEASON', 'SCORE', ':', ['3', '+', '3'], '=', '6']] 
['03/02/03','S03-1234','31/111-22-1003',['GLEASON', 'GRADE', ['4', '+', '3'], '=', '7']] 
['03/02/03','S03-1234','31/111-22-1003',['GLEASON', 'SCORE', ':', '7', '=', ['4', '+', '3']]] 
['04/17/04','S04-123','30/111-22-1004',['GLEASON', 'SCORE', ':', ['3', '+', '4', '-', '7']]] 
['05/28/05','S05-1234','20/111-22-1005',['GLEASON', 'SCORE', '7', '[', ['3', '+', '4'], ']']] 
['06/18/06','S06-10686','20/111-22-1006',['GLEASON', ['4', '+', '3']]] 
['06/18/06','S06-10686','20/111-22-1006',['GLEASON', 'PATTERN', '5']] 
['07/22/07','S07-2749','20/111-22-1007',['GLEASON', 'SCORE', '6', '(', ['3', '+', '3'], ')']] 

다음은 문법

num = Word(nums) 
arith_expr = operatorPrecedence(num, 
    [ 
    (oneOf('-'), 1, opAssoc.RIGHT), 
    (oneOf('* /'), 2, opAssoc.LEFT), 
    (oneOf('+ -'), 2, opAssoc.LEFT), 
    ]) 
accessionDate = Combine(num + "/" + num + "/" + num)("accDate") 
accessionNumber = Combine("S" + num + "-" + num)("accNum") 
patMedicalRecordNum = Combine(num + "/" + num + "-" + num + "-" + num)("patientNum") 
score = (Optional(oneOf('([')) + 
     arith_expr('lhs') + 
     Optional(oneOf(') ]')) + 
     Optional(oneOf('= -')) + 
     Optional(oneOf('([')) + 
     Optional(arith_expr('rhs')) + 
     Optional(oneOf(') ]'))) 
gleason = Group("GLEASON" + Optional("SCORE") + Optional("GRADE") + Optional("PATTERN") + Optional(":") + score) 
patientData = Group(accessionDate + accessionNumber + patMedicalRecordNum) 
partMatch = patientData("patientData") | gleason("gleason") 

및 출력 기능입니다.

lastPatientData = None 
for match in partMatch.searchString(TEXT): 
    if match.patientData: 
     lastPatientData = match 
    elif match.gleason: 
     if lastPatientData is None: 
      print "bad!" 
      continue 
     # getParts() 
     FOUT.write("['{0.accDate}','{0.accNum}','{0.patientNum}',{1}]\n".format(lastPatientData.patientData, match.gleason)) 

출력에서 ​​보는 것처럼 좋지 않습니다. 필자는 파일에 쓰고 일부 구문을 위장한 것입니다. 나는 그 (것)들과 일할 수있다 그래야 pyparsing 중간 결과의 ahold를 얻는 방법에 고투하고있다. 이 스크립트를 작성하고 중복 된 스크립트를 찾는 두 번째 스크립트를 실행해야합니까?

업데이트, Paul McGuire의 대답을 기반으로합니다. 이 함수의 출력은 엔트리 당 하나의 행을 찾았지만 지금은 점수 조각을 잃어 버리고 있습니다 (각 글리슨 점수는 지적으로, 형태는 primary + secondary = total입니다. 이것은 데이터베이스로 향하고 있으므로 pri, sec, tot는 별도의 posgresql 열, 또는 파서의 출력, 쉼표로 구분 된 값)

accumPatientData = None 
for match in partMatch.searchString(TEXT): 
    if match.patientData: 
     if accumPatientData is not None: 
      #this is a new patient data, print out the accumulated 
      #Gleason scores for the previous one 
      writeOut(accumPatientData) 
     accumPatientData = (match.patientData, []) 
    elif match.gleason: 
     accumPatientData[1].append(match.gleason) 
if accumPatientData is not None: 
    writeOut(accumPatientData) 

는 이제 출력은 내가 거기에 다시 도달하고 일부를 잡아 싶습니다이

01/01/01,S01-12345,20/111-22-1001,9 
02/02/02,S02-1234,20/111-22-1002,6 
03/02/03,S03-1234,31/111-22-1003,7,4+3 
04/17/04,S04-123,30/111-22-1004, 
05/28/05,S05-1234,20/111-22-1005,3+4 
06/18/06,S06-10686,20/111-22-1006,, 
07/22/07,S07-2749,20/111-22-1007,3+3 

처럼 보인다 그 잃어버린 요소들, 재 배열, 누락 된 것들을 찾아서 다시 넣으십시오.이 유사 코드와 같은 것 :

def diceGleason(glrhs,gllhs) 
    if glrhs.len() == 0: 
     pri = gllhs[0] 
     sec = gllhs[2] 
     tot = pri + sec 
     return [pri, sec, tot] 
    elif glrhs.len() == 1: 
     pri = gllhs[0] 
     sec = gllhs[2] 
     tot = glrhs 
     return [pri, sec, tot] 
    else: 
     pri = glrhs[0] 
     sec = glrhs[2] 
     tot = gllhs 
     return [pri, sec, tot] 

업데이트 2 : 좋아, Paul은 멋지지만 나는 바보입니다. 그가 말한 것과 정확히 똑같은 것을 시도해 본 결과 pri, sec, tot을 얻기 위해 몇 가지 방법을 시도했지만 실패했습니다. 다음과 같은 오류가 계속 발생합니다.

Traceback (most recent call last): 
    File "Stage1.py", line 81, in <module> 
    writeOut(accumPatientData) 
    File "Stage1.py", line 47, in writeOut 
    FOUT.write("{0.accDate},{0.accNum},{0.patientNum},{1.pri},{1.sec},{1.tot}\n".format(pd, gleaso 
nList)) 
AttributeError: 'list' object has no attribute 'pri' 

이러한 AttributeError는 내가 계속 받고있는 것입니다. 분명히 나는 ​​무슨 일이 일어나고 있는지 이해하지 못한다. (폴, 나는 책을 가지고있다. 나는 그것이 내 앞에 열려 있고, 나는 이해하지 못한다고 맹세한다.) 여기에 my script이 있습니다. 잘못된 장소에 뭔가 있습니까? 결과를 잘못 부른 건가요?

+1

"원하는 출력"파일에 대한 링크가 끊어진 것 같습니다. – Michael0x2a

+0

고마워요! – Niels

+0

하나의 환자 데이터에 대해 여러 글리슨 점수가 정의되어있는 경우 어떻게해야하는지 알 수 없습니다. 첫 번째 걸릴까요? 마지막 하나? 또는 그들은 중복되어 있으며 어떤 것을 가져 가야합니까? – PaulMcG

답변

2

파서를 한 번 변경하지 않았지만 파싱 코드를 약간 변경했습니다.

"중복"을 실제로 얻지는 못했지만 글리슨 점수를 볼 때마다 현재 환자 데이터를 인쇄하고 환자 데이터 레코드 중 일부는 여러 글리슨 점수 항목을 포함합니다. 난 당신이 뭘 하려는지 이해, 여기에 의사 코드 나는 따를 것입니다 :

accumulator = None 
foreach match in (patientDataExpr | gleasonScoreExpr).searchString(source): 

    if it's a patientDataExpr: 
     if accumulator is not None: 
      # we are starting a new patient data record, print out the previous one 
      print out accumulated data 
     initialize new accumulator with current match and empty list for gleason data 

    else if it's a gleasonScoreExpr: 
     add this expression into the current accumulator 

# done with the for loop, do one last printout of the accumulated data 
if accumulator is not None: 
    print out accumulated data 

을이 아주 쉽게 파이썬으로 변환 :

def printOut(patientDataTuple): 
    pd,gleasonList = patientDataTuple 
    print("['{0.accDate}','{0.accNum}','{0.patientNum}',{1}]".format(
     pd, ','.join(''.join(gl.rhs) for gl in gleasonList))) 

accumPatientData = None 
for match in partMatch.searchString(TEXT): 
    if match.patientData: 
     if accumPatientData is not None: 
      # this is a new patient data, print out the accumulated 
      # Gleason scores for the previous one 
      printOut(accumPatientData) 

     # start accumulating for a new patient data entry 
     accumPatientData = (match.patientData, []) 

    elif match.gleason: 
     accumPatientData[1].append(match.gleason) 
    #~ print match.dump() 

if accumPatientData is not None: 
    printOut(accumPatientData) 

나는 덤핑 있다고 생각하지 않습니다 Gleason 데이터를 바르게 출력 할 수 있지만 여기에서 조정할 수 있습니다.

편집 :

당신은 gleason에 대한 구문 분석 작업으로 diceGleason을 연결하고이 동작을 얻을 수 있습니다 :

def diceGleasonParseAction(tokens): 
    def diceGleason(glrhs,gllhs): 
     if len(glrhs) == 0: 
      pri = gllhs[0] 
      sec = gllhs[2] 
      #~ tot = pri + sec 
      tot = str(int(pri)+int(sec)) 
      return [pri, sec, tot] 
     elif len(glrhs) == 1: 
      pri = gllhs[0] 
      sec = gllhs[2] 
      tot = glrhs 
      return [pri, sec, tot] 
     else: 
      pri = glrhs[0] 
      sec = glrhs[2] 
      tot = gllhs 
      return [pri, sec, tot] 

    pri,sec,tot = diceGleason(tokens.gleason.rhs, tokens.gleason.lhs) 

    # assign results names for later use 
    tokens.gleason['pri'] = pri 
    tokens.gleason['sec'] = sec 
    tokens.gleason['tot'] = tot 

gleason.setParseAction(diceGleasonParseAction) 

당신은 당신이 tot를 얻을 수 prisec 합산 한 오타가 있었지만,이은을 모든 문자열을 추가 했으므로 '3'과 '4'를 추가하고 '34'를 얻습니다. 추가 작업을 수행 할 int로 변환하는 것이 모두 필요했습니다. 그렇지 않으면 diceGleasondiceGleasonParseAction에 내부적으로 보관하여 새로운 결과 이름으로 구문 분석 된 토큰을 매듭 짓는 메커니즘에서 pri, sectot을 추론 할 논리를 분리했습니다. 구문 분석 조치는 새로운 내용을 반환하지 않으므로 토큰은 현재 위치에서 업데이트되고 나중에 전달되어 출력 메소드에서 나중에 사용됩니다.

+0

Paul, 다시 한번 감사드립니다. 당신은 아마 당신에게 그것을 가르쳐 준 것보다 더 많은 시간을 가르쳐 주었을 것입니다. 그래서 나는 두 배로 감사하고 있습니다. 나는 그것을 약간 조정했다. 그러나 나는 아직도 점수의 조각을 잃어 버리고있다. == A == 튜플 대신 목록이 붙어 있다고 생각합니다. 테스트 케이스를 읽으면 케이스 6은 4 + 3 = 7을 의미하고 5 차 (보통은보고되지 않음) 점수가 5라고 말합니다. 따라서 7 튜플이 짧은 요소라는 것을 의미합니다. == B == 여전히 오른쪽에 1 차 및 2 차 점수가 나타나는 것을 재정렬 할 수 없습니다. – Niels

+0

나는 이것이 마지막으로 고집하는 지점을 살펴보기를 희망하지만 나는 이것을 받아 들인 것으로 표시했다 : 나는 계속해서 속성 오류를 얻는다. 파일은 http://nielsolson.us/pastebin/에있다. – Niels