파일을 구문 분석하는 방법

파일을 구문 분석하는 방법

다음 file1.txt가 있습니다. 내가 하고 싶은 것은 value1을 value7로 변환하여 한 줄에 출력하는 것입니다. 값은 "Start"와 "End"라는 단어 사이에서 검색됩니다. 레이블/값이 누락된 경우 출력에 "NA"가 표시됩니다.

아래에서 원하는 output.txt를 참조하세요.

간단히 말해서 Start와 End 사이의 값을 복사하여 한 줄에 출력하고 싶습니다. 값 레이블이 없으면 값에 NA가 표시됩니다. 그리고 file1.txt를 찾을 때까지 계속해서 다른 레코드의 값을(처음부터 끝까지) 검색합니다.

파일 1.txt

Start

label1  label2  label3 label4

value1  value2  value3 value4

label5

value5

label6  label7

value6  value7

End


Start

label1  label2  label4

valueA  valueB  valueD

label5

valueE

label6 

valueF  

End


Start
.
.
.
End

출력.txt

label1 label2 label3 label4 label5 label6 label7

value1 value2 value3 value4 value5 value6 value7

valueA valueB NA     valueD valueE valueF NA

답변1

이 Python 스크립트는 원하는 작업을 수행해야 합니다.

#!/usr/bin/env python
# -*- encoding: ascii -*-
"""parse.py

Parses a custom-format data-file.
Processes the file first and then prints the results.
"""

import sys

# Read the data from the file
file = open(sys.argv[1], 'r')

# Initialize a dictionary to collect the values for each label
labels = {}

# Initialize a stack to keep track of block state
stack = []

# Initialize a counter to count the number of blocks
block = 0

# Process the file
line = file.readline()
while line:

    # Remove white-space
    line = line.strip()

    # The stack should be empty when we start a new block
    if line.lower() == "start":
        if stack:
            raise Exception("Invalid File Format: Bad Start")
        else:
            stack.append(line)

    # Otherwise the bottom of the stack should be a "Start"
    # When we reach the end of a block we empty the stack
    # end increment the block counter
    elif line.lower() == "end":
        if stack[0].lower() != "start":
            raise Exception("Invalid File Format: Bad End")
        else:
            block += 1
            stack = []

    # Other lines should come in consecutive label/value pairs
    # i.e. a value row should follow a label row
    elif line:

        # If there are an odd number of data rows in the stack then
        # the current row should be a value row - check that it matches
        # the corresponding label row
        if len(stack[1:])%2==1:

            _labels = stack[-1].split()
            _values = line.split()

            # Verify that the label row and value row have the same number
            # of columns
            if len(_labels) == len(_values):
                stack.append(line)
                for label, value in zip(_labels, _values):

                    # Add new labels to the labels dictionary
                    if label not in labels:
                        labels[label] = {
                            "cols": len(label)
                        }

                    # Add the value for the current block
                    labels[label][block] = value

                    # Keep track of the longest value for each label
                    # so we can format the output later
                    if len(value) > labels[label]["cols"]:
                        labels[label]["cols"] = len(value)
            else:
                raise Exception("Invalid File Format: Label/Value Mismatch")

        # If there are an even number of data rows in the stack then
        # the current row should be a label row - append it to the stack
        else:
            stack.append(line)

    # Read the next line
    line = file.readline()

# Construct the header row
header = ""
for label in labels:
    cols = labels[label]["cols"]
    header += "{0: <{width}}".format(label, width=cols+1)

# Construct the data rows
rows = []
for i in range(0, block):
    row = ""
    for label in labels:
        cols = labels[label]["cols"]
        row += "{0: <{width}}".format(labels[label].get(i, "NA"), width=cols+1)
    rows.append(row)

# Print the results
print(header)
for row in rows:
    print(row)

다음과 같이 실행할 수 있습니다.

python parse.py file1.txt

샘플 데이터에 대해 다음 출력을 생성합니다.

label1 label2 label3 label4 label5 label6 label7
value1 value2 value3 value4 value5 value6 value7
valueA valueB NA     valueD valueE valueF NA

관련 정보