IT·개발

Python 개행문자 제거 3가지 방법 — 실무 비교 정리

5월 16, 2026 2 min read

파일을 줄 단위로 읽으면 줄 끝에 \n이 붙어 있어, 이후 처리 과정에서 거슬리는 상황이 있습니다. 2021년에 올렸던 원본 포스팅은 map + lambda + strip 한 가지 패턴만 보여줬는데, 제목에 “3가지 방법”이라 써두고 본문은 하나뿐이었던 비대칭이 계속 마음에 걸렸습니다. 5년이 지난 지금, 나머지 두 패턴을 더해 다시 정리합니다. Python 3 기준이며 외부 라이브러리 없이 표준 라이브러리만 사용합니다. 세 패턴을 코드와 함께 한꺼번에 비교합니다.

왜 개행문자가 따라붙는가

Python 3 표준 동작에 따라, f.readlines()는 파일을 줄 단위로 읽으면서 각 줄 끝의 \n까지 포함해 반환합니다. 아래 예시를 보면 바로 감이 옵니다.

# 가상 입력: abc.txt에 두 줄이 있다고 가정
# Line 1: hello
# Line 2: world

f = open('abc.txt', 'r')
lines = f.readlines()
print(lines)
# 출력: ['hello\n', 'world\n']

\n이 섞인 채로 문자열 비교·파싱·출력에 들어가면 예상치 못한 결과가 생깁니다. 그래서 읽은 직후 한 단계 손질이 필요합니다.

덧붙여, with open('abc.txt', 'r') as f: 형태의 컨텍스트 매니저를 쓰면 블록을 빠져나올 때 파일이 자동으로 닫힙니다. 이후 방법 ②③에서는 이 패턴을 활용하고, 방법 ①은 원본 코드 형태를 그대로 보여줍니다.

방법 ① map + lambda + strip — 원본 코드

원본(2021)에서 소개한 패턴입니다.

f = open('abc.txt', 'r')
lines = f.readlines()
lines = list(map(lambda s: s.strip(), lines))

※ 원본 코드에는 f.close() 호출이 없습니다. 실제 사용 시에는 with open('abc.txt', 'r') as f: 블록으로 감싸 파일이 자동으로 닫히도록 하는 것을 권장합니다.

아래 한 줄에 네 가지 요소(list / map / lambda / strip())가 들어 있습니다.

  • strip(): 문자열 앞뒤의 모든 공백 문자(스페이스·탭·개행)를 제거합니다. 인자를 따로 지정하지 않으면 \n도 함께 지워집니다.
  • lambda s: s.strip(): 문자열을 받아 strip() 결과를 바로 반환하는 익명 함수입니다. return 없이 표현식 값이 그대로 반환됩니다.
  • map(함수, iterable): lines의 각 요소에 lambda를 적용하고, 그 결과를 묶어 반환합니다.
  • list(...): map 결과를 리스트로 변환합니다. map만 쓰면 map 객체로 반환되므로, 리스트로 사용하려면 list()로 감싸야 합니다.

가상 입력 ['hello\n', 'world\n']을 기준으로 결과는 ['hello', 'world']가 됩니다. 함수형 스타일에 익숙하면 깔끔하게 읽히지만, 코드 리뷰 자리에서 한 번 더 들여다보게 되는 형태이기도 합니다.

방법 ② 리스트 컴프리헨션 + strip

리스트 컴프리헨션을 쓰면 같은 처리를 다음처럼 직관적으로 표현할 수 있습니다.

with open('abc.txt', 'r') as f:
    lines = [s.strip() for s in f.readlines()]

가상 입력 ['hello\n', 'world\n']을 기준으로 결과는 ['hello', 'world']입니다. 방법 ①과 의미상 동일합니다.

앞서 설명한 컨텍스트 매니저(with open(...))를 적용했습니다. map + lambda 중첩 없이 “각 줄에서 strip한다”는 의도가 바로 읽히는 게 이 방법의 장점입니다.

방법 ③ rstrip(‘\n’) — 개행만 정확히 제거

strip()은 줄 앞쪽 들여쓰기까지 함께 지운다는 점이 문제가 될 수 있습니다. 개행만 정확히 지우고 싶다면 rstrip('\n')을 씁니다.

with open('abc.txt', 'r') as f:
    lines = [s.rstrip('\n') for s in f.readlines()]

인자 없는 strip()은 문자열 앞쪽의 들여쓰기(스페이스·탭)까지 함께 지웁니다. 들여쓰기가 의미를 가지는 텍스트, 예를 들어 코드 파일이나 들여쓴 마크다운을 읽을 때는 rstrip('\n')이 의도에 더 가깝습니다.

차이를 직접 비교하면 이렇습니다.

# 가상 입력: 앞쪽에 들여쓰기가 있는 줄
sample = ['  hello\n', '  world\n']

# strip() — 앞쪽 공백도 함께 제거
print([s.strip() for s in sample])
# 출력: ['hello', 'world']

# rstrip('\n') — 줄 끝 \n만 제거, 앞쪽 공백 유지
print([s.rstrip('\n') for s in sample])
# 출력: ['  hello', '  world']

“이게 더 정확합니다”가 아니라, 의도가 “개행만 지우겠다”라면 rstrip('\n')이 그 의도를 더 명확하게 표현합니다.

어떤 방법을 쓸까 — 짧은 비교

방법코드 형태어울리는 상황
① map + lambda + striplist(map(lambda s: s.strip(), lines))함수형 스타일, 한 줄 처리 선호 시
② 리스트 컴프리헨션 + strip[s.strip() for s in lines]가독성 우선, 가장 흔히 보이는 형태
③ rstrip(‘\n’)[s.rstrip('\n') for s in lines]앞쪽 들여쓰기·공백을 그대로 보존할 때

세 방법 모두 Python 표준 문법·동작 범위 안에서 외부 라이브러리 없이 동작합니다. 성능 수치보다는 코드를 함께 읽는 사람과 프로젝트 컨벤션에 맞는 쪽을 고르는 게 자연스럽습니다.

5년 뒤 한마디

비교표로 기준을 정리했으니, 개인적인 한마디를 덧붙이면 —

2021년에 처음 정리할 때는 map + lambda로 한 줄에 처리하는 게 멋져 보였습니다. 지금 같은 코드를 다시 짠다면, 가독성 때문에 리스트 컴프리헨션 쪽을 먼저 꺼낼 것 같습니다. 어느 쪽이 절대적으로 낫다기보다, 팀이나 프로젝트 코딩 스타일에 맞춰 고르는 게 자연스럽다는 생각입니다. rstrip('\n')은 별로 쓸 일이 없다고 생각했는데, 들여쓰기가 있는 텍스트를 다루다 보니 꺼내게 되는 경우가 생각보다 있더라고요.

팩트 구간: 세 방법 모두 Python 3 표준 동작 기준으로 동일하거나 유사한 결과를 냅니다. 회고 구간: “지금이라면 리스트 컴프리헨션을 먼저 꺼낼 것 같다”는 작성자의 개인 판단입니다.

마무리

파일을 한 줄씩 다루는 작업은 자동화 스크립트의 출발점이 되는 경우가 많습니다. 이 작은 개행 손질 하나가 이후 처리 전체를 깔끔하게 만들어 줍니다. 파일을 읽은 직후 strip 패턴 하나를 팀 컨벤션으로 고정해 두면, 이후 처리 내내 개행 문제를 신경 쓸 일이 줄어듭니다.


참고: str.strip() · str.rstrip() 메서드의 공식 정의는 아래와 같습니다.

str.strip([chars]) — Return a copy of the string with leading and trailing characters removed. str.rstrip([chars]) — Return a copy of the string with trailing characters removed.

출처: Python 3 공식 문서 — Built-in Types, String Methods: <https://docs.python.org/3/library/stdtypes.html#string-methods>