Stellar Brief
알아두면 유용한 정보

개발 가이드

멀쩡해 보이는 CSV가 깨지는 이유 — 재현으로 확인한 사례 4가지

작성: 게시:

멀쩡해 보이는 CSV가 깨지는 이유 — 재현으로 확인한 사례 4가지

CSV는 “쉼표로 구분된 텍스트”라는 단순한 형식처럼 보이지만, 실무에서는 이 단순함이 함정입니다. 텍스트 편집기로 열면 멀쩡해 보이는 파일이 프로그램에서는 열이 밀리고, 행이 사라지고, 한글이 외계어가 됩니다.

이 글은 그런 문제를 증상이 비슷한 사례 4가지로 나눠, 각 사례를 실제 파서로 재현한 결과와 함께 분석합니다. 파서 동작 재현에는 PowerShell 7의 ConvertFrom-Csv(RFC 4180 계열의 실전 파서)를, 인코딩 재현에는 Node.js v22.14.0의 TextDecoder를 사용했습니다.

사례 1. 열이 밀렸는데, 알고 보니 데이터가 사라져 있었다

증상: 특정 행에서만 열이 어긋나거나, 있어야 할 값의 뒷부분이 없습니다.

주소나 회사명처럼 쉼표가 들어갈 수 있는 값이 따옴표 없이 저장된 경우입니다. 재현해 보겠습니다.

name,city
Kim,Seoul, Gangnam

사람 눈에는 “Kim의 도시는 Seoul, Gangnam”으로 읽히지만, 파서가 읽은 결과는 다릅니다.

name : Kim
city : Seoul

" Gangnam"은 어디에도 없습니다. 헤더가 2열이라 파서는 세 번째 조각을 버렸고, 에러는 나지 않았습니다. 이 사례가 위험한 이유가 이것입니다. 열 밀림은 눈에 보이기라도 하는데, 파서에 따라서는 이렇게 조용히 데이터가 유실됩니다. 같은 값을 따옴표로 감싸면 정상적으로 읽힙니다.

Kim,"Seoul, Gangnam"

name : Kim
city : Seoul, Gangnam

해결: 쉼표가 들어갈 수 있는 열(주소, 메모, 회사명)은 내보내는 쪽에서 따옴표로 감싸야 합니다. 받은 파일이라면, 행별 열 개수를 검사해서 어느 행이 어긋났는지부터 찾는 것이 순서입니다.

사례 2. 어느 행부터 뒤가 통째로 사라졌다

증상: 파일에는 분명 100행이 있는데 프로그램에는 30행만 보입니다.

닫히지 않은 따옴표 하나가 원인일 수 있습니다. 4행짜리 데이터에서 2행의 따옴표를 닫지 않고 재현해 봤습니다.

name,note
Kim,"hello
Lee,world
Park,ok

결과는 이렇습니다.

name : Kim
note : hello
       Lee,world
       Park,ok

Lee와 Park의 행이 사라진 게 아니라, Kim의 note 필드 안으로 삼켜졌습니다. 파서는 닫는 따옴표를 찾을 때까지 줄바꿈이든 쉼표든 전부 하나의 값으로 취급하기 때문에, 따옴표 하나가 파일 끝까지의 모든 행을 흡수할 수 있습니다. “특정 행 이후가 다 사라졌다”는 증상은 대부분 그 직전 행의 따옴표 문제입니다.

해결: 값 안에 따옴표를 넣어야 한다면 ""로 이스케이프합니다("5"" 디스플레이"). 받은 파일이라면 사라지기 시작한 지점 근처의 행에서 홀수 개의 따옴표를 찾으면 됩니다.

사례 3. 데이터 행 수와 파일 줄 수가 다르다

증상: 에디터로는 3줄인데 파서는 1행이라고 합니다. 행 수 기준으로 짠 스크립트가 어긋납니다.

이건 깨진 게 아니라 CSV의 정상 동작입니다. 따옴표로 감싼 필드 안에는 줄바꿈이 들어갈 수 있습니다.

name,memo
Kim,"line1
line2"

이 파일을 파서에 넣으면 레코드 수는 1입니다. 텍스트로는 3줄, 데이터로는 헤더 1행 + 레코드 1행인 것이죠. 그래서 “줄 수 = 행 수”를 가정하고 split('\n')이나 행 단위 스트리밍으로 CSV를 처리하는 코드는 이런 파일에서 반드시 어긋납니다. 사례 2가 사고라면, 사례 3은 이 정상 동작을 모르는 코드가 사고를 만드는 경우입니다.

해결: CSV를 직접 파싱하지 말고 따옴표를 이해하는 파서 라이브러리를 쓰는 것이 원칙입니다. 사례 1에서 본 것처럼 순진한 쉼표 split은 값 속 쉼표에서도 깨집니다.

사례 4. 한글이 외계어가 됐다

증상: 이름,나이�대�,��� 같은 문자로 보입니다. 열 구조는 멀쩡합니다.

이건 CSV 구조의 문제가 아니라 인코딩 불일치입니다. 같은 바이트를 다른 인코딩으로 해석하면 어떻게 되는지 재현해 봤습니다.

원본(UTF-8)              : 이름,나이 / 김철수,30
EUC-KR로 잘못 읽으면      : �대�,��� / 源泥��,30
반대로 EUC-KR 원본을
UTF-8로 잘못 읽으면       : �̸�,����

UTF-8 파일을 EUC-KR(CP949)로 읽으면 源泥 같은 엉뚱한 한자가 섞여 나오고, 반대 방향이면 (대체 문자)가 가득해집니다. 깨진 모양을 보면 어느 방향의 불일치인지 짐작할 수 있는 셈입니다. 한국어 환경에서 흔한 조합은 “UTF-8로 저장한 CSV를 구버전 Excel이 CP949로 여는 경우”와 그 반대입니다.

해결: 데이터를 만드는 쪽과 여는 쪽의 인코딩을 맞춰야 합니다. Excel과 주고받는 파일이라면 UTF-8 with BOM으로 저장하는 것이 가장 무난하고, 이미 받은 파일이 깨져 보인다면 에디터에서 인코딩을 바꿔가며 다시 열어보면 됩니다. 글자가 깨져 보여도 바이트 자체는 보통 온전하므로, 원본을 다시 받을 필요까지는 없는 경우가 많습니다.

구조 문제인지부터 가려내기

사례 1~3은 구조(열 개수·따옴표) 문제이고, 사례 4는 인코딩 문제입니다. 둘은 원인도 해결도 다르므로 먼저 어느 쪽인지 가려내는 것이 진단의 첫 단계입니다.

구조 쪽은 Stellar Brief의 CSV First Aid에 데이터를 붙여넣으면 구분자를 감지하고 행별 열 개수와 닫히지 않은 따옴표를 검사해서, 어느 행에서 깨졌는지 짚어줍니다. 입력한 데이터는 브라우저에서만 처리되며 서버로 전송되지 않습니다. 반대로 글자 자체가 깨져 보인다면 사례 4의 인코딩 문제이므로, 열 구조를 검사하기 전에 인코딩부터 맞추는 것이 순서입니다.

#CSV #데이터 #Excel #인코딩 #EUC-KR #UTF-8 #개발 도구

이 글에 대하여

작성:

Stellar Brief는 가능한 경우 공식 자료와 확인 가능한 출처를 우선 참고해 콘텐츠를 작성합니다.

Stella 소개 콘텐츠 작성 및 편집 원칙

관련 글