CSV가 오류 없이 열렸는데 한글이 깨지거나 첫 머리글만 찾지 못한다면, 쉼표부터 고치기 전에 원본 바이트를 어떤 인코딩으로 문자로 읽었는지와 파일 맨 앞 BOM을 어떻게 처리했는지 확인해야 한다. 디코딩 성공은 의도한 문자를 읽었다는 보증이 아니고, 눈에 같은 머리글도 실제 문자열이 다를 수 있다.
이 글은 CSV를 프로그램이나 스프레드시트에 가져오는 담당자를 위한 설명이다. ‘이름,수량’과 ‘가나,2’는 합성 자료다. 로컬 Python에서 바이트·문자·머리글을 대조했으며 실제 Excel·Calc나 업무 DB의 동작을 시험하지 않았다.
파일 이름이 아니라 바이트와 생산 조건을 본다
CSV 확장자는 문자 인코딩을 확정하지 않는다. 생산 시스템의 내보내기 설정·전달 계약을 먼저 확인하고 원본 파일의 바이트를 보존한다. 같은 파일을 열 때마다 임의의 인코딩으로 다시 저장하면, 어느 단계에서 문자가 달라졌는지 찾기 어려워진다.
Python의 codecs 문서는 외부 정보 없이 인코딩을 신뢰성 있게 결정할 수 없다는 한계를 설명한다. 합성 UTF-8 파일을 Latin-1로 엄격하게 디코딩했을 때도 예외는 없었지만 원래 한글과 다른 문자열이 나왔다. 이 경우에는 잘못 읽은 문자열을 같은 Latin-1로 다시 바이트화하면 원래 바이트로 돌아갔다. 그러나 원래 인코딩과 중간 변환을 아는 이 특정 조건의 확인이지, 깨진 한글을 언제나 복원할 수 있다는 뜻은 아니다.
| 로컬에서 확인한 조건 | 관측 결과 | 판단의 한계 |
|---|---|---|
| UTF-8 한글 바이트를 Latin-1로 읽음 | 예외 없음, 원문과 다른 문자 | ‘열렸다’를 올바른 인코딩의 증거로 삼지 않는다. |
| 바이트 FF를 UTF-8 strict로 읽음 | UnicodeDecodeError | 이 바이트열이 UTF-8 규칙에 맞지 않음을 확인할 뿐, 정답 인코딩을 알아낸 것은 아니다. |
| 같은 FF를 replace로 읽고 UTF-8로 저장 | 대체문자 U+FFFD, 원래 FF와 다른 바이트 | 대체된 텍스트만으로 원래 바이트를 복구했다고 할 수 없다. |
실제 코드를 작성한다면 encoding과 오류 처리 정책을 명시해 검사할 수 있다. errors='ignore'로 오류를 숨기거나 대체문자를 지우는 방식은 원문을 보존하는 조치가 아니다. 원본이 남아 있다면 확인한 인코딩으로 원본부터 다시 읽고, 대체문자로 저장된 복사본만 남았다면 확인할 수 없는 손실을 구별한다.
UTF-8 BOM은 첫 머리글 앞 문자로 남을 수 있다
Unicode의 BOM 안내에 따르면 UTF-8의 선두 바이트 EF BB BF는 서명으로 쓰일 수 있다. UTF-8의 바이트 순서를 바꾸는 표시는 아니며 일부 수신자는 BOM을 기대하지 않는다. BOM이 없다는 사실만으로 특정 인코딩을 확정할 수도 없다.
합성 UTF-8 CSV 앞에 이 세 바이트를 붙여 Python에서 읽었다. 일반 utf-8로 디코딩한 뒤 CSV 파싱을 하면 첫 머리글은 U+FEFF + 이름이 됐고, utf-8-sig로 읽으면 이름이었다. 같은 글자로 보이더라도 ‘이름’ 키를 찾는 코드의 비교 결과는 달라질 수 있다.

Python의 utf-8-sig 안내는 선두의 선택적 UTF-8 BOM을 디코딩 때 건너뛰는 동작을 설명한다. 다음은 UTF-8과 선택적 선두 BOM을 받기로 정한 파일에 적용할 수 있는 예다. CP949 등 다른 인코딩의 파일을 이 코드 하나로 모두 읽는다는 뜻은 아니다.
import csv
with open('input.csv', encoding='utf-8-sig', newline='') as f:
reader = csv.DictReader(f)
header = reader.fieldnames
# header가 계약의 실제 머리글과 일치하는지 따로 확인한다.
BOM을 무조건 붙이거나 지우는 처방은 피한다
Microsoft의 Excel 안내는 BOM이 있는 UTF-8 CSV의 열기와, 그렇지 않을 때 Power Query의 Text/CSV 가져오기 또는 텍스트 가져오기 경로를 설명한다. 이는 Excel에 관한 제품 안내다. 모든 소비자가 BOM을 요구한다거나 BOM을 붙이면 필드 타입·수식·머리글 문제까지 해결된다는 보장은 아니다.
반대로 첫 머리글이 안 맞는다고 파일 전체에서 U+FEFF나 공백을 일괄 삭제해서도 안 된다. 파일 선두의 서명 처리와 값 안의 문자를 수정하는 일은 다르다. 실제 첫 키의 코드 포인트·바이트 위치를 확인하고, 생산자와 소비자가 합의한 위치와 조건에만 변환을 적용한다.
원본→문자→필드→업무값 순서로 점검한다
- 원본 바이트와 내보내기 인코딩·BOM 계약을 확보한다.
- 확인된 디코더로 읽고 첫 머리글·한글·의심 문자의 실제 문자열을 비교한다.
- 그 다음 구분자·따옴표 규칙으로 레코드와 필드를 읽는다.
- 마지막으로 숫자·날짜·빈 값과 소비 프로그램의 해석이 원래 업무 뜻을 유지하는지 확인한다.
이 순서는 작성자의 진단 제안이다. 필드가 갈라지면 CSV 구조 파싱, 문자값은 맞지만 셀이 계산식으로 취급되면 수식 해석 경계로 나눈다. 번호가 달라진 문제는 식별자 정밀도 확인, 원문에 없던 시각을 더한 문제는 날짜·시간대의 의미 보존과 구별한다.
처음부터 이미지의 문자가 다르게 추출됐다면 원문·OCR·후속 답변의 최초 불일치 확인이 필요하다. 이 글의 디코딩 비교가 OCR 오독을 고쳐 주거나 원본 없는 손실을 복원하는 것은 아니다.
자주 묻는 질문
깨진 한글이 보이면 UTF-8로 다시 저장하면 되나요?
잘못 읽은 문자를 그대로 UTF-8로 저장하면 깨진 결과가 굳어질 수 있다. 원본 바이트와 실제 내보내기 인코딩을 먼저 확인한다. 원본이 남아 있는 재디코딩과, 손실된 복사본의 문자 치환은 다른 작업이다.
strict 디코딩을 통과하면 인코딩이 맞다는 뜻인가요?
선택한 디코더가 그 바이트를 받아들였다는 뜻이다. 원문과 같은 문자라는 보장은 아니다. 이 글의 Latin-1 예처럼 예외 없이 다른 문자가 될 수 있어, 알려진 머리글과 대표 값을 함께 대조해야 한다.
첫 머리글이 안 맞으면 항상 BOM 문제인가요?
아니다. 공백·다른 머리글·잘못된 구분자나 인코딩도 원인일 수 있다. 실제 키의 문자와 원본 선두 바이트를 보고 판단한다. BOM이 확인되지 않은 파일에 제거 규칙을 무조건 적용하지 않는다.
“CSV 한글이 깨지거나 첫 머리글이 안 맞을 때: 인코딩과 BOM 점검”에 대한 2개의 생각