2013-08-09 2 views
2

StackOverflow를 둘러 보았고 특정 질문에 대한 대답을 찾을 수 없으므로 뭔가 놓친 경우 용서해주십시오.파일에 마지막 줄 바꿈 문자를 쓰지 마십시오.

import re 

target = open('output.txt', 'w') 

for line in open('input.txt', 'r'): 
    match = re.search(r'Stuff', line) 
    if match: 
     match_text = match.group() 
     target.write(match_text + '\n') 
    else: 
     continue 
target.close() 

파싱 할 파일이 너무 커서 한 줄씩 처리해야합니다.

물론 이것은 파일 끝에 추가 줄 바꿈 문자를 남깁니다.

'if match'루프의 최종 반복에서 파일의 끝에 추가 개행 문자를 넣지 않도록이 코드를 어떻게 변경해야합니까? 마지막에 파일을 다시 살펴보고 마지막 줄을 제거해야합니까? (비효율적으로 보이지만)?

내가 찾은 기존 StackOverflow 질문은 파일에서 모든 새 줄을 제거하는 것으로 나타났습니다.

이 코드를 작성하는 데 더 많은 pythonic/효율적인 방법이 있다면 나는 또한 내 자신의 학습을위한 제안을 환영합니다.

도움 주셔서 감사합니다.

+3

파일 끝에있는 개행 문자가 "추가"되지 않습니다. 마지막 줄의 개행 문자입니다. – kindall

+0

사람들은 일반적으로 최종 줄 바꿈을 유지합니다. 그래서 다른 많은 예를 보지 못합니다. – tdelaney

+0

흥미로운 점은 @tdelaney입니다. 나는 그것에 대해 생각해 보지 않았고, 많은 상황에서 그것이 정말로 큰 관심사가 아니라고 생각합니다. –

답변

6

다음 줄의 처음에 각 줄의 개행 문자를 입력하십시오. 줄. 첫 번째 줄의 시작 부분에 줄 바꿈을 쓰지 않으려면 빈 문자열로 초기화 된 변수를 사용하고 루프의 줄 바꿈을 설정하십시오.

import re 

with open('input.txt') as source, open('output.txt', 'w') as target: 

    newline = '' 
    for line in source: 
     match = re.search(r'Stuff', line) 
     if match: 
      target.write(newline + match.group()) 
      newline = '\n' 

는 또한 비트가 (그 밖의 무엇이하기 위하여려고? 루프이기 때문에 else: continue이 필요하지 않습니다) 코드를 재구성하고, 파일이 자동으로 닫혀 있도록 with 문을 사용하도록 변경되었습니다.

0

원하는 것부터 가장 짧은 경로는 결과를 목록에 저장 한 다음 목록을 개행 문자와 결합하여 파일에 기록하는 것입니다.

import re 

target = open('output.txt', 'w') 
results = [] 

for line in open('input.txt', 'r'): 
    match = re.search(r'Stuff', line) 
    if match: 
     results.append(match.group()) 
target.write("\n".join(results)) 
target.close() 

음성 시작 또는 끝 부분에 새 줄 바꿈이 없습니다. 결과 목록의 규모가 아주 크지 않을 수도 있습니다. (그리고 얼마 남지 않은 것처럼 내가 else을 생략했다)

+0

* 구문 분석하는 파일은 ** 거대한 **이므로 한 줄씩 처리해야합니다. * –

+0

처음에는이 파일을 고려했지만 파일이 너무 커서 사용중인 컴퓨터의 메모리에 맞출 수 없었습니다. –

3

당신이 할 수있는 또 다른 일은 truncate이다. .tell()은 파일의 현재 바이트 수를 알려줍니다. 우리는 그 다음 하나를 뺀 다음 거기에서 잘라서 후행 줄 바꿈을 제거합니다.

리눅스와 맥 OS에
with open('a.txt', 'w') as f: 
    f.write('abc\n') 
    f.write('def\n') 
    f.truncate(f.tell()-1) 

-1는 정확하지만 Windows에서이 -2 할 필요가있다. os.linesep을 확인하는 것의 더 평범한 결정 방법.

import os 
remove_chars = len(os.linesep) 

with open('a.txt', 'w') as f: 
    f.write('abc\n') 
    f.write('def\n') 
    f.truncate(f.tell() - remove_chars) 

kindal의 대답은 당신이 큰 파일 말했습니다을 제외하고, 또한 유효합니다. 이 방법을 사용하면 기가 바이트의 RAM에서 테라 바이트 크기의 파일을 처리 할 수 ​​있습니다.

1

동일한 정규 표현식을 반복해서 수행하기 때문에 사전에 컴파일하고 싶을 것입니다.

import re 
prog = re.compile(r'Stuff') 

난 편의상 stdinstdout로의 입력 및 출력에 경향이있다. 그러나 그것은 맛의 문제 (및 스펙)입니다. 제거에 대한 특정 요구 사항을 무시

from sys import stdin, stdout 

최종 EOL [1] 당신의 자신의 학습, 다음과 같이 기록 할 수있는 모든 일에 대한 비트 주소 :

from itertools import imap 
stdout.writelines(match.group() for match in imap(prog.match, stdin) if match) 

[1 ] 다른 사람들이 논평 한 것처럼, 이것은 나쁜 것입니다. 누군가가 이것을 할 때 매우 짜증납니다.

+0

작은 문자열에 대한 다시 검색을 수행하여 10,000 회 반복하는 스크립트. 두 번째 버전은 다시 컴파일합니다. 첫 번째 re.py 라인은 2300000 번, 두 번째는 10,001 번을 참조했습니다. 동일한 파일의 192 행에 대해 한 번 더합니다. 두 번째 버전에는 40k 함수 호출이 있었고 첫 번째 예제 (30k 함수 호출)의 두 배가 걸렸습니다. –

+0

* 두 번째가 re.py 라인 230의 [_compile()에 참조 함] 10,001 번 * : @ChristoferOhlsson 정규식을 한 번만 컴파일하는 대신 10,001 번 정규식을 컴파일하는 것으로 보입니다. 당신은 [여기에있는 예제에서와 같이 * 미리 컴파일 된 정규 표현식을 사용 했습니까?] (https://docs.python.org/2/library/re.html#re.compile)? – antak

관련 문제