.txt 데이터 편집용 프로그램 작성 - Python 또는 Unix?

.txt 데이터 편집용 프로그램 작성 - Python 또는 Unix?

나는 프로그래밍 경험이 거의 없으며 현재 기술을 향상시키기 위해 노력하고 있습니다. 기본적으로 .txt 파일의 일부 데이터에 대해 특정 처리를 수행할 수 있는 프로그램을 작성해야 합니다.

처음부터 다음과 같은 데이터가 포함된 .txt 파일이 있습니다.

>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrstuv
>tex_4 abcdefghijklmnopqrst
//     x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrst
>tex_4 abcdefghijklmnopqrstuv
//         x  x
>tex_1 abcdefghijklmnopqrstuv
>tex_2 abcdefghijklmnopqrstuv
//     x   x

내가 사용하고 있는 소프트웨어에서 분석할 수 있는 데이터 세트를 얻으려면 이 데이터로 몇 가지 이상한 작업을 수행해야 합니다. 각 "//..." 줄은 다음 "//..." 줄까지 위의 데이터 그룹을 나타냅니다.

내가 하고 싶은 일의 목록은 다음과 같습니다.

참조하는 데이터 그룹이 위가 아닌 아래에 있도록 "//..." 줄을 이동합니다.

//         x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrstuv
>tex_4 abcdefghijklmnopqrst
//         x  x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrst
>tex_4 abcdefghijklmnopqrstuv
//              x   x
>tex_1 abcdefghijklmnopqrstuv
>tex_2 abcdefghijklmnopqrstuv

줄의 나머지 텍스트를 이동하지 않고 // 뒤에 각 그룹에 고유한 이름을 추가합니다.

//Name 1  x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrstuv
>tex_4 abcdefghijklmnopqrst
//Name 2   x  x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrst
>tex_4 abcdefghijklmnopqrstuv
//Name 3        x   x
>tex_1 abcdefghijklmnopqrstuv
>tex_2 abcdefghijklmnopqrstuv

원본 파일을 변경하지 않고 새 파일로 출력합니다. 그런 다음 아래의 각 이름 행 + 행을 잡고 File2에 출력합니다.

//Name 1  x
>tex_1 abcdefghijklmnopqrstu
//Name 2   x  x
>tex_1 abcdefghijklmnopqrstu
//Name 3        x   x
>tex_1 abcdefghijklmnopqrstuv

구조를 변경하고 다음과 같이 이름을 지정한 후 File3에 출력합니다.

>Name 1 abcdefghijklmnopqrstu
>Name 2 abcdefghijklmnopqrstu
>Name 3 abcdefghijklmnopqrstuv

위의 데이터는 구조이므로 실제로 분석할 수 있습니다.

이제 나는 이것이 어려운 작업이라는 것을 알고 있습니다. "어떻게 프로그래밍합니까?"라고 묻는 것이 아닙니다. 이런 프로젝트를 어디에서 시작하시겠습니까? 이 프로젝트에 어떤 언어가 가장 적합하다고 생각하시나요?

저는 이 사이트에서 도움을 받아 UNIX에서 몇 가지 작업을 수행할 수 있었습니다. 예를 들어, 다음 Unix 코드를 사용하여 각 "//..." 줄에 고유한 이름을 지정합니다.

awk -F '' '/\/\//{n++ ; t=" Name "n ; sub("// {0,"length(t)-1"}","//"t)}{print}' File1.txt

어디서부터 시작해야 할지 몇 가지 팁을 주실 수 있나요?
이 질문이 Python 프로젝트에 적합한가요?
원시 .txt 데이터 파일에는 많은 양의 데이터가 포함되어 있으므로 수동으로 처리할 수 없습니다. 또한 이 프로젝트는 프로그래밍을 더 깊이 탐구하는 방법입니다.

답변1

나에게 이것은 파이썬 작업처럼 보입니다. 일반적인 경험 법칙: 작업에 "플랫" 및 콘텐츠 블라인드 처리만 필요한 경우 핵심 유틸리티(바람직하게는 gnu)가 최선의 선택입니다. 이는 문자열 대체, 삭제, 줄 기반 처리, 간단한 정렬, 계산, 필터링 등에 작동합니다. 이러한 도구를 사용하면 원하는 작업을 매우 빠르게 수행하는 코드 줄을 작성할 수 있으며 연습을 통해 이러한 작업을 수행할 수 없습니다. 심지어 많은 생각이 필요합니다.

반면에 계층적(트리와 같은) 구조, 사용자 정의 구분 기호 및 컨텍스트 인식 문자열을 암시하는 파일 보기가 필요한 복잡한 작업이 있는 경우 파일 언어에서 동일한 구조를 사용하여 프로그래밍하는 것이 더 쉬울 것입니다. 극단적인 예는 html/xml/json 파일, 중괄호가 중첩된 모든 파일 등입니다. 사용 가능한 매우 강력한 데이터 구조가 있는 경우(Python에서는 가능), 읽은 후 Object is handler andexit와 같은 곳에 작성하면 됩니다. . 여전히 awk에서(또는 sed에서 조금 더 노력하면) 할 수 있지만 그만한 가치는 없습니다.

귀하의 경우에는 이전 마크의 위치를 ​​기억해야 합니다(또는 긴 버퍼를 유지해야 합니다). 이는 라인 처리 소프트웨어에 약간 다루기 어렵습니다. 하지만 파이썬에서는 이것이 쉽습니다.

샘플 코드:

#!/usr/bin/python
import sys

with open(sys.argv[1],'r') as file, open(sys.argv[2],'w') as file1, open(sys.argv[3],'w') as file2, open(sys.argv[4],'w') as file3:
    counter = 1
    current_buffer = []
    for line in file:
        if line.startswith('//'):
            #we found a delimiter, flush the buffer
            #could use regular expressions, but for the sake of this example
            #this is enough
            prefix = '//Name {}'.format(counter)
            new_header = prefix+line[len(prefix):]
            file1.write(new_header)
            file2.write(new_header)
            for oldline in current_buffer:
                file1.write(oldline)
            if current_buffer: #only first line to file 2
                first_line = current_buffer[0]
                file2.write(first_line)
                #same here, could use regular expressions from "import re" but we don't have to
                rest_of_line = first_line.split(' ',1)[1]
                file3.write('//Name {} {}\n'.format(counter,rest_of_line.strip()))
            current_buffer=[]
            counter+=1
        else:
            current_buffer.append(line)

    #if the file is well-formatted, current_buffer should be empty now - otherwise, do special handling

전화해서 ./test.py inputfile file1 file2 file3그것이 당신이 원하는 것인지 확인하세요.

답변2

가장 편안한 방법을 선택해야 합니다. 즉, 새로운 도구 사용법을 배우는 것도 피해서는 안 됩니다. 저는 이 도구에 매우 만족 sed하며 특히 이 작업에 적합하다고 생각하여 nl두 도구를 조합하여 사용합니다.

<<\INFILE \
nl -bp'^//' -w1 -s'      ' |\
sed -ne ' s|^ *>|>|;//H;x;//x;t' -e 'G
        x;s|.*|### The following is written to: File1|p
        x;s|\([0-9]*\)\( *\)\( \)*//\2|//Name \1\3|pw File1
        x;s|1|2|p;x;s|\n\(\n.*\)*|&&|2;s|||2p;w File2' -e 'x;s|2|3|p
        x;s|//\([^ ]* [^ ]*\).*\n[^ ]*|>\1|pw File3'
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrstuv
>tex_4 abcdefghijklmnopqrst
//     x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrst
>tex_4 abcdefghijklmnopqrstuv
//         x  x
>tex_1 abcdefghijklmnopqrstuv
>tex_2 abcdefghijklmnopqrstuv
//     x   x

...이것이 트릭을 수행하는 것 같습니다.

내가 말할 때nl이 작업에 매우 적합--separator패턴에 따라 블록을 순차적으로 쉽게 번호를 매기고 , 번호가 매겨진 줄의 텍스트와 줄 번호 사이에 임의의 문자열을 삽입하는 것 외에도 nl줄은 항상 들여쓰기되기 때문입니다.번호 없음추가하는 들여쓰기와 일치하도록 합니다.

^//이는 패턴과 일치 하도록 번호가 매겨지지 않은 모든 줄이 이제 <space>. 따라서 실제 텍스트가 예제의 데이터보다 훨씬 더 복잡하더라도 sed실제로는 매우 쉽습니다. 실제로 위 작업의 대부분은 의미 있는 디버그 출력을 생성하는 것입니다 sed. 완전한 기능을 갖춘 명령문은 다음과 같이 간단할 수 있습니다.

nl -bp'^//' -w1 -s'      ' <infile |
sed -ne 's|^ *>|>|;//H;x;//x;t' -e 'G;h
         s|\([0-9]*\)\( *\)\( \)*//\2|//Name \1\3|w File1
         s|\n|&&|2;s|\n\n.*||;w File2
         s|//\([^ ]* [^ ]*\).*\n[^ ]*|>\1|w File3'

나는 당신의 말에 조금 혼란스러워요줄의 나머지 텍스트를 이동하지 마십시오왜냐하면 그것은 당신의 예와 모순되는 것 같기 때문입니다.(그리고 가능성의 영역). 내가 이렇게 말하는 이유는 다음과 같습니다.

//     x

...분명히 양도됐어조금오른쪽으로 변환되면 다음과 같습니다.

//Name 1  x

...사실은1그리고엑스두 예제 모두에서 동일한 열을 차지합니다. 중간에 이 모순을 해결하려고 노력 중입니다. 문자가 아닌 항목을 덮어쓰지 않는 한 텍스트를 이동하지 않고 쌍과 공백을 <space>계속 삽입합니다 .Name [num]

따라서... 사이의 차이는 고려되지 않습니다.

//Name 3        x   x

...그리고...

//     x   x

...무시했습니다(희망?)예제의 버그입니다.

내 파이프는 모든 것을 표준 출력으로 인쇄하지만, 다음으로 시작하는 줄 뒤의 블록 ###도 지정된 파일에 차례로 추가됩니다. 내 파이프라인이 인쇄하는 내용은 다음과 같습니다.

### The following is written to: File1
//Name 1 x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrstuv
>tex_4 abcdefghijklmnopqrst
### The following is written to: File2
//Name 1 x
>tex_1 abcdefghijklmnopqrstu
### The following is written to: File3
>Name 1 abcdefghijklmnopqrstu
### The following is written to: File1
//Name 2   x  x
>tex_1 abcdefghijklmnopqrstu
>tex_2 abcdefghijklmnopqrstuv
>tex_3 abcdefghijklmnopqrst
>tex_4 abcdefghijklmnopqrstuv
### The following is written to: File2
//Name 2   x  x
>tex_1 abcdefghijklmnopqrstu
### The following is written to: File3
>Name 2 abcdefghijklmnopqrstu
### The following is written to: File1
//Name 3 x   x
>tex_1 abcdefghijklmnopqrstuv
>tex_2 abcdefghijklmnopqrstuv
### The following is written to: File2
//Name 3 x   x
>tex_1 abcdefghijklmnopqrstuv
### The following is written to: File3
>Name 3 abcdefghijklmnopqrstuv

답변3

이 경우 Python이 더 적합하다는 데 동의하지 않습니다. 어려운 줄 조작이 없습니다. 변수를 설정하고 다양한 변수 세트를 인쇄하기만 하면 됩니다. 이것이 일반적인 bash 작업입니다. 따라서 awk대신 내가 선호하는 몇 가지 계산이 필요합니다 sed(일반적인 텍스트 조작 프로그램).

awk -F '' '
          /\/\//{
                 n++
                 t="Name "n" "
                 sub("// {0,"length(t)"}","//"t)
                 print $0 "\n" l1 l2 > "File2"
                 print $0 "\n" l1 > "File3"
                 sub("[^ ]* ","<"t,l1)
                 print l1 > "data.file" 
                 l1=""
                 l2=""
                 next
                 }
          {
                 if (l1=="")
                     l1=$0
                 else l2=l2 "\n" $0
                 }' Input.txt

그러나 모든 사람은 자신이 더 잘 아는 도구를 선호합니다.

PS 입력 문자열의 길이에 관해서. OP가 귀하의 예를 확인하면 볼 수 있습니다«x» is above «e»

//         x
>tex_1 abcdefghijklmnopqrstu

하지만 들어가고 나면Name 1 «x» is above «d»

//Name 1  x
>tex_1 abcdefghijklmnopqrstu

length(t)따라서 스크립트에서는 lenght(t)-1. 또한 이름 스크립트를 입력할 공간이 충분하지 않은 경우 문자열의 나머지 부분을 오른쪽으로 이동해야 합니다.

관련 정보