CSV 첫 열 이름이 id인데 못 찾을 때: UTF-8 BOM 확인하기
한글은 멀쩡한데 프로그램이 id 열을 찾지 못한다면 파일 앞의 BOM이 열 이름에 남았는지 확인하세요. UTF-8 BOM이 있는 합성 파일을 두 가지 방식으로 읽어 차이를 재현합니다.
원인
UTF-8 BOM은 파일 선두의 EF BB BF 바이트입니다. 읽는 방식에 따라 이 서명이 문자 U+FEFF로 남으면 첫 헤더가 id가 아니라 \ufeffid가 됩니다. 눈에 비슷하게 보여도 문자열은 다릅니다. Python의 utf-8-sig는 파일 선두의 UTF-8 서명을 처리합니다. Python codecs 공식 문서
BOM이 있다고 모든 프로그램이 실패하는 것은 아닙니다. 받는 시스템이 요구하는 형식을 먼저 확인합니다.
재현
06-header-bom.csv는 BOM 뒤에 id,memo와 합성 데이터 A1,연습자료를 담았습니다. 파일과 같은 폴더에서 실행합니다.
import csv
from pathlib import Path
raw = Path('06-header-bom.csv').read_bytes()
a = next(csv.reader(raw.decode('utf-8').splitlines()))
b = next(csv.reader(raw.decode('utf-8-sig').splitlines()))
print(raw[:3].hex())
print(repr(a[0]), repr(b[0]))
print(a[0] == 'id', b[0] == 'id')
출력은 efbbbf, '\ufeffid' 'id', False True입니다. 화면의 글자가 아닌 실제 문자열을 비교해야 원인을 구별할 수 있습니다. 위 splitlines()는 이 예제의 한 줄짜리 헤더 확인용입니다. 일반 CSV 전체를 이렇게 분할해 읽지 않습니다.
해결
Python으로 읽는 쪽을 바꿀 수 있다면 BOM 유무를 처리하는 utf-8-sig로 열고 CSV 파서에 전달합니다.
with open('06-header-bom.csv', encoding='utf-8-sig', newline='') as f:
rows = list(csv.reader(f, strict=True))
assert rows[0][0] == 'id'
받는 프로그램이 BOM 없는 UTF-8을 요구한다면 새 사본으로 저장합니다. 원본을 덮어쓰지 않습니다.
Path('06-header-no-bom.csv').write_bytes(raw.decode('utf-8-sig').encode('utf-8'))
06-header-no-bom.csv는 변환 결과입니다. 올바르게 읽은 두 파일의 헤더·셀 값이 같음을 확인했습니다.
연결 도구: 인코딩 변환
CSV 도우미의 **인코딩 변환(/convert-encoding/)에서 예제를 고르고 입력을 UTF-8, 출력을 UTF-8로 지정해 BOM 없는 사본을 받는 흐름입니다. UTF-8 (BOM, 엑셀 권장)**은 BOM을 붙이는 다른 출력이므로 받는 프로그램의 요구에 맞춰 고릅니다. 자동 선택된 출력이 목적과 같다고 가정하지 말고 직접 확인하세요.
변환 후 헤더와 한글을 다시 확인합니다. 이 예제의 예상 결과는 Python과 현재 도구의 인코딩 라이브러리로 대조합니다. 브라우저 버튼 조작을 이번 글 제작에서 실행한 것은 아닙니다.
한계
공백·다른 철자·중복 헤더·구분자 오류도 열을 찾지 못하는 원인입니다. BOM만 제거한다고 모두 해결되지 않습니다. 본문 셀 안의 U+FEFF까지 일괄 삭제하지 마세요. 이 글은 단일 선두 BOM이 있는 UTF-8 파일만 다루며, 중복 BOM이나 다른 인코딩은 별도 진단이 필요합니다. 이미 손상된 글자는 BOM 변환으로 복원되지 않습니다.
검토일: 2026-10-18. Python 3.9.6·합성 데이터로 선두 바이트, 헤더 비교, BOM 없는 사본의 값 보존을 검증했습니다. Excel GUI는 필요하지 않으며 실행하지 않았습니다.
AI 보조 작성: AI로 초안·합성 예제를 작성하고 실행 결과를 확인했습니다. 실제 고객 자료는 사용하지 않았습니다. 참고용이며 원본과 수신 시스템의 규격을 함께 대조하세요.