python 파싱 여러 txt 파일의 파이썬 구문 분석 텍스트




파이썬 파일 읽기 배열 (2)

"프레젠테이션"과 "질문 및 답변"섹션 만 필요로하는지 확인해주십시오. 또한 출력과 관련하여 CSV 형식을 "수동으로 변환"한 것과 비슷한 형식으로 덤프하는 것이 좋습니다.

제공 한 모든 샘플 파일에 대해 작동하도록 업데이트 된 솔루션.

"Parsed-transcript"파일을 공유 할 때마다 셀 "D : H"에서 출력됩니다.

#state = ["other", "head", "present", "qa", "speaker", "data"]
# codes : 0, 1, 2, 3, 4, 5
def writecell(out, data):
    out.write(data)
    out.write(",")

def readfile(fname, outname):
    initstate = 0
    f = open(fname, "r")
    out = open(outname, "w")
    head = ""
    head_written = 0
    quotes = 0
    had_speaker = 0
    for line in f:
        line = line.strip()
        if not line: continue
        if initstate in [0,5] and not any([s for s in line if "=" != s]):
            if initstate == 5:
                out.write('"')
                quotes = 0
                out.write("\n")
            initstate = 1
        elif initstate in [0,5] and not any([s for s in line if "-" != s]):
            if initstate == 5:
                out.write('"')
                quotes = 0
                out.write("\n")
                initstate = 4
        elif initstate == 1 and line == "Presentation":
            initstate = 2
            head = "Presentation"
            head_written = 0
        elif initstate == 1 and line == "Questions and Answers":
            initstate = 3
            head = "Questions and Answers"
            head_written = 0
        elif initstate == 1 and not any([s for s in line if "=" != s]):
            initstate = 0
        elif initstate in [2, 3] and not any([s for s in line if ("=" != s and "-" != s)]):
            initstate = 4
        elif initstate == 4 and '[' in line and ']' in line:
            comma = line.find(',')
            speech_st = line.find('[')
            speech_end = line.find(']')
            if speech_st == -1:
                initstate = 0
                continue
            if comma == -1:
                firm = ""
                speaker = line[:speech_st].strip()
            else:
                speaker = line[:comma].strip()
                firm = line[comma+1:speech_st].strip()
            head_written = 1
            if head_written:
                writecell(out, head)
                head_written = 0
            order = line[speech_st+1:speech_end]
            writecell(out, speaker)
            writecell(out, firm)
            writecell(out, order)
            had_speaker = 1
        elif initstate == 4 and not any([s for s in line if ("=" != s and "-" != s)]):
            if had_speaker:
                initstate = 5
                out.write('"')
                quotes = 1
            had_speaker = 0
        elif initstate == 5:
            line = line.replace('"', '""')
            out.write(line)
        elif initstate == 0:
            continue
        else:
            continue
    f.close()
    if quotes:
        out.write('"')
    out.close()

readfile("Sample1.txt", "out1.csv")
readfile("Sample2.txt", "out2.csv")
readfile("Sample3.txt", "out3.csv")

세부

이 솔루션에는 다음과 같이 작동하는 상태 머신이 있습니다 : 1. 제목이 있는지 여부를 감지합니다. 예이면 제목을 쓰고 스피커를 감지합니다. 3. 스피커에 메모를 씁니다. 4. 다음 스피커로 전환합니다. ...

나중에 csv 파일을 원하는대로 처리 할 수 ​​있습니다. 기본 처리가 완료되면 원하는 형식으로 데이터를 채울 수도 있습니다.

편집하다:

"writecell"기능을 교체하십시오.

def writecell(out, data):
    data = data.replace('"', '""')
    out.write('"')
    out.write(data)
    out.write('"')
    out.write(",")

사전을 만들기 위해 여러 텍스트 파일에서 항목을 채굴하는 방법에 대한 조언을 구합니다.

이 텍스트 파일은 https://pastebin.com/Npcp3HCM

수동으로 필요한 데이터 구조로 변환되었습니다. https://drive.google.com/file/d/0B2AJ7rliSQubV0J2Z0d0eXF3bW8/view

이러한 텍스트 파일은 수천 가지이며 다음 예제와 같이 섹션 제목이 다를 수 있습니다.

  1. https://pastebin.com/wWSPGaLX
  2. https://pastebin.com/9Up4RWHu

나는 그 파일들을 읽음으로써 시작했다.

from glob import glob

txtPth = '../tr-txt/*.txt'
txtFiles = glob(txtPth)

with open(txtFiles[0],'r') as tf:
    allLines = [line.rstrip() for line in tf]

sectionHeading = ['Corporate Participants',
                  'Conference Call Participiants',
                  'Presentation',
                  'Questions and Answers']

for lineNum, line in enumerate(allLines):
    if line in sectionHeading:
        print(lineNum,allLines[lineNum])

내 생각은 섹션 제목이있는 행 번호를 찾고 해당 행 번호 사이의 내용을 추출한 다음 대시와 같은 구분 기호를 제거하는 것입니다. 그게 효과가 없었고 나는 이런 종류의 사전을 만들어서 나중에 채석 된 아이템에 대한 다양한 자연 언어 처리 알고리즘을 실행할 수 있도록 노력했습니다.

{file-name1:{
    {date-time:[string]},
    {corporate-name:[string]},
    {corporate-participants:[name1,name2,name3]},
    {call-participants:[name4,name5]},
    {section-headings:{
        {heading1:[
            {name1:[speechOrderNum, text-content]},
            {name2:[speechOrderNum, text-content]},
            {name3:[speechOrderNum, text-content]}],
        {heading2:[
            {name1:[speechOrderNum, text-content]},
            {name2:[speechOrderNum, text-content]},
            {name3:[speechOrderNum, text-content]},
            {name2:[speechOrderNum, text-content]},
            {name1:[speechOrderNum, text-content]},
            {name4:[speechOrderNum, text-content]}],
        {heading3:[text-content]},
        {heading4:[text-content]}
        }
    }
}

문제는 다른 파일의 제목과 제목이 다를 수 있다는 것입니다. 그러나 항상 "프레젠테이션"이라는 섹션이 있으며 "질문 및 답변"섹션이있을 가능성이 큽니다. 이 섹션 제목은 항상 등호 기호로 구분됩니다. 다른 화자의 내용은 항상 대시 문자열로 구분됩니다. Q & A 섹션의 "음성 명령"은 대괄호 안에 숫자로 표시됩니다. 참가자는 항상 문서의 시작 부분에 이름 앞에 별표가 표시되며 타일은 항상 다음 줄에 있습니다.

텍스트 파일을 구문 분석하는 방법에 대한 제안이 있으면 감사하겠습니다. 이상적인 도움은 데이터베이스에 쓰여질 수있는 각 파일에 대해 사전 (또는 다른 적절한 데이터 구조)을 생성하는 방법에 대한 지침을 제공하는 것입니다.

감사

--편집하다--

파일 중 하나는 다음과 같습니다. https://pastebin.com/MSvmHb2e

"질문 및 답변"섹션은 "프레젠테이션"으로 잘못 표시되며 다른 "질문 및 답변"섹션은 없습니다.

마지막 샘플 텍스트는 https://pastebin.com/jr9WfpV8


코드의 주석은 모든 것을 설명해야합니다. 아무 것도 지정되지 않았 으면 알려주고 더 많은 의견이 필요합니다.

간단히 말해서 정규 표현식을 활용하여 전체 텍스트를 하위 섹션으로 나누는 '='구분 기호 줄을 찾은 다음 명확하게 구분하기 위해 각 유형의 섹션을 별도로 처리합니다 (각 사례를 처리하는 방법을 알 수 있도록).

참고 사항 : 나는 '참석자'와 '저자'라는 단어를 같은 의미로 사용하고 있습니다.

편집 : 프리젠 테이션 / 품질 관리 섹션의 참석자 / 작성자 옆에있는 '[x]'패턴을 기반으로 정렬하도록 코드를 업데이트했습니다. pprint가 OrderedDict를 잘 처리하지 못하기 때문에 pretty print 부분을 변경했습니다.

문자열에 \n 포함하여 추가 공백을 제거하려면 str.strip() 됩니다. 특별히 \n 만을 제거해야한다면 str.strip('\n') .

나는 회담에서 공백을 제거하도록 코드를 수정했다.

import json
import re
from collections import OrderedDict
from pprint import pprint


# Subdivides a collection of lines based on the delimiting regular expression.
# >>> example_string =' =============================
#                       asdfasdfasdf
#                       sdfasdfdfsdfsdf
#                       =============================
#                       asdfsdfasdfasd
#                       =============================
# >>> subdivide(example_string, "^=+")
# >>> ['asdfasdfasdf\nsdfasdfdfsdfsdf\n', 'asdfsdfasdfasd\n']
def subdivide(lines, regex):
    equ_pattern = re.compile(regex, re.MULTILINE)
    sections = equ_pattern.split(lines)
    sections = [section.strip('\n') for section in sections]
    return sections


# for processing sections with dashes in them, returns the heading of the section along with
# a dictionary where each key is the subsection's header, and each value is the text in the subsection.
def process_dashed_sections(section):

    subsections = subdivide(section, "^-+")
    heading = subsections[0]  # header of the section.
    d = {key: value for key, value in zip(subsections[1::2], subsections[2::2])}
    index_pattern = re.compile("\[(.+)\]", re.MULTILINE)

    # sort the dictionary by first capturing the pattern '[x]' and extracting 'x' number.
    # Then this is passed as a compare function to 'sorted' to sort based on 'x'.
    def cmp(d):
        mat = index_pattern.findall(d[0])
        if mat:
            print(mat[0])
            return int(mat[0])
        # There are issues when dealing with subsections containing '-'s but not containing '[x]' pattern.
        # This is just to deal with that small issue.
        else:
            return 0

    o_d = OrderedDict(sorted(d.items(), key=cmp))
    return heading, o_d


# this is to rename the keys of 'd' dictionary to the proper names present in the attendees.
# it searches for the best match for the key in the 'attendees' list, and replaces the corresponding key.
# >>> d = {'mr. man   ceo of company   [1]' : ' This is talk a' ,
#  ...     'ms. woman  ceo of company    [2]' : ' This is talk b'}
# >>> l = ['mr. man', 'ms. woman']
# >>> new_d = assign_attendee(d, l)
# new_d = {'mr. man': 'This is talk a', 'ms. woman': 'This is talk b'}
def assign_attendee(d, attendees):
    new_d = OrderedDict()
    for key, value in d.items():
        a = [a for a in attendees if a in key]
        if len(a) == 1:
            # to strip out any additional whitespace anywhere in the text including '\n'.
            new_d[a[0]] = value.strip()
        elif len(a) == 0:
            # to strip out any additional whitespace anywhere in the text including '\n'.
            new_d[key] = value.strip()
    return new_d


if __name__ == '__main__':
    with open('input.txt', 'r') as input:
        lines = input.read()

        # regex pattern for matching headers of each section
        header_pattern = re.compile("^.*[^\n]", re.MULTILINE)

        # regex pattern for matching the sections that contains
        # the list of attendee's (those that start with asterisks )
        ppl_pattern = re.compile("^(\s+\*)(.+)(\s.*)", re.MULTILINE)

        # regex pattern for matching sections with subsections in them.
        dash_pattern = re.compile("^-+", re.MULTILINE)

        ppl_d = dict()
        talks_d = dict()

        # Step1. Divide the the entire document into sections using the '=' divider
        sections = subdivide(lines, "^=+")
        header = []
        print(sections)
        # Step2. Handle each section like a switch case
        for section in sections:

            # Handle headers
            if len(section.split('\n')) == 1:  # likely to match only a header (assuming )
                header = header_pattern.match(section).string

            # Handle attendees/authors
            elif ppl_pattern.match(section):
                ppls = ppl_pattern.findall(section)
                d = {key.strip(): value.strip() for (_, key, value) in ppls}
                ppl_d.update(d)

                # assuming that if the previous section was detected as a header, then this section will relate
                # to that header
                if header:
                    talks_d.update({header: ppl_d})

            # Handle subsections
            elif dash_pattern.findall(section):
                heading, d = process_dashed_sections(section)

                talks_d.update({heading: d})

            # Else its just some random text.
            else:

                # assuming that if the previous section was detected as a header, then this section will relate
                # to that header
                if header:
                    talks_d.update({header: section})

        #pprint(talks_d)
        # To assign the talks material to the appropriate attendee/author. Still works if no match found.
        for key, value in talks_d.items():
            talks_d[key] = assign_attendee(value, ppl_d.keys())

        # ordered dict does not pretty print using 'pprint'. So a small hack to make use of json output to pretty print.
        print(json.dumps(talks_d, indent=4))




nlp