CSV 쉼표·따옴표·줄바꿈, split으로 읽으면 왜 열이 틀어질까

이 카테고리 글 목록

전체글 보기

문서 AI나 업무 프로그램이 내보낸 CSV에서 메모 한 칸에 쉼표와 줄바꿈이 들어가면, split(',')이나 한 줄씩 자르는 코드가 열과 레코드를 잘못 나눌 수 있다. 물리적인 줄을 먼저 자르지 말고, 생산자와 합의한 구분자·따옴표 규칙으로 CSV를 파싱한 뒤 머리글·필드 수·값의 대응을 검사해야 한다. 읽기에 성공한 것과 원래 표를 복원한 것은 다른 결과다.

이 글은 이미 확보한 문자 데이터를 CSV로 전달하는 담당자를 위한 설명이다. 아래 문의 데이터는 실제 고객 정보가 아닌 합성 자료다. 로컬 Python에서 파싱 결과를 확인했으며 Excel·Calc의 실제 가져오기나 AI 모델의 추출 정확도를 시험한 결과는 아니다.

CSV의 한 레코드는 화면의 한 줄과 다를 수 있다

RFC 4180의 형식 설명은 쉼표·큰따옴표·줄바꿈이 있는 필드를 큰따옴표로 감싸고, 필드 안의 큰따옴표는 두 번 쓰는 방식을 설명한다. 이 문서는 널리 쓰이는 공통 형식을 정리한 Informational RFC이며 모든 CSV 소비자를 강제하는 인터넷 표준은 아니다. 실제 프로그램이 어떤 구분자와 인용 규칙을 쓰는지 함께 확인해야 한다.

다음 예제에서 문의 a1의 메모는 쉼표, 따옴표와 줄바꿈을 포함한 하나의 필드다. 바깥따옴표는 필드 경계를 표시하고, ""A""는 값 안의 "A"를 표현한다.

id,note,quantity
a1,"도시, 지점 ""A""
재방문",2
a2,일반 문의,1

합성 파일은 레코드 사이에 CRLF, 메모 안에는 LF를 넣어 Python의 처리 결과를 확인했다. 위 표시에는 물리적으로 네 줄이 있지만, CSV 파서가 반환한 것은 머리글을 포함한 세 레코드와 레코드마다 세 필드였다. 데이터 문의는 두 건이다. RFC 예시의 줄바꿈 관례와 이 로컬 입력의 구체적인 줄바꿈은 구별한다.

열 수가 우연히 맞아도 값은 잘못 나뉠 수 있다

이 예제의 두 번째 물리 줄을 쉼표로만 자르면 조각이 세 개 나온다. 머리글도 세 칸이어서 정상처럼 보이지만, 실제 세 번째 조각은 수량 2가 아니라 메모의 일부다. 다음 줄에는 메모의 나머지와 수량이 남는다. 따라서 ‘열 개수 하나가 맞음’만으로 전체 파일을 통과시켜서는 안 된다.

같은 평가 카드가 청록색과 노란색 두 목록으로 나뉘고 돋보기로 실패 카드를 살펴보는 삽화
같은 입력을 두 결과와 대조하는 기존 AI 생성 개념도. 원래 필드와 파싱 결과의 대응을 비교하는 맥락으로 재사용했다. 실제 CSV 화면·열 개수나 파서 성능을 나타내는 그림은 아니다.

Python csv 문서도 읽은 줄 수와 반환된 레코드 수가 다를 수 있다고 설명한다. 파일을 열 때는 인코딩을 명시하고 newline=''로 CSV 모듈에 줄바꿈 처리를 맡기는 방식이 안내돼 있다. 아래는 이 글의 합성 파일과 같은 계약으로 읽는 예다. 수식 평가나 업무 처리는 하지 않는다.

import csv

with open('input.csv', encoding='utf-8', newline='') as f:
    rows = list(csv.reader(f, delimiter=',', quotechar='"', strict=True))

strict=True는 파서가 잘못된 CSV 입력을 만났을 때 오류를 내도록 하는 옵션이다. 기대한 머리글, 필드 수, 업무상 값의 뜻까지 정의해 주는 옵션은 아니다. 다른 구분자를 지정한 파일도 오류 없이 한 필드로 읽힐 수 있다.

생산자·소비자의 계약을 먼저 맞춘다

또 다른 합성 입력 id;memo와 a1;확인을 쉼표 구분자로 읽으면 각 레코드는 한 필드로 반환됐고 예외는 없었다. 세미콜론 구분자로 읽으면 의도한 두 필드가 된다. 파싱 성공이라는 표시보다 실제 계약과 미리보기 결과를 봐야 하는 이유다.

확인할 경계 검사할 내용 잘못됐을 때의 판단
구분자·인용 규칙 쉼표/세미콜론, 큰따옴표, 내부 따옴표와 줄바꿈 처리 파일 이름만 보고 추정하지 않고 내보내기·가져오기 설정을 맞춘다.
머리글 존재 여부, 실제 이름·순서·중복과 필수 열 첫 레코드를 무조건 데이터나 머리글로 버리지 않는다.
레코드 구조 파싱한 모든 레코드의 필드 수와 식별값 잘못 나뉜 일부 줄을 새 행으로 받아들이지 않는다.
값의 대응 같은 문의의 메모·수량이 원래 값과 같은지 열 수가 같아도 원문/생성 전 데이터와 대조한다.

이 표는 작성자의 점검 제안이다. 머리글이 없는 CSV도 있을 수 있으므로 존재 여부부터 계약에 포함한다. Python의 dialect 설정이나 소비 앱의 가져오기 화면을 사용하더라도 자동 추정 결과는 실제 값과 대조할 대상이다. 모든 CSV 변형을 하나의 기본값으로 읽을 수 있다고 가정하지 않는다.

파싱 이후의 의미와 셀 해석은 따로 확인한다

레코드와 필드를 복원했더라도 빈 칸이 미확인인지 0인지까지 결정되지는 않는다. 그 문제는 누락·null·빈 문자열·0을 구별하는 기준과 연결된다. 반대로 이미지에서 값을 추출할 때부터 행이 틀렸다면 OCR 표의 값·행·열 대응 확인으로 돌아가야 한다. CSV 파서는 잘못 추출된 원문을 고쳐 주지 않는다.

올바르게 인용한 필드도 소비 프로그램이 다르게 해석할 수 있다. CSV 인용과 스프레드시트 수식 해석의 차이를 따로 확인하고, 글자가 깨지거나 첫 머리글만 맞지 않는다면 인코딩과 BOM 점검을 먼저 적용한다.

자주 묻는 질문

모든 필드를 큰따옴표로 감싸면 파싱 문제가 끝나나요?

같은 인용 규칙을 쓰는 소비자라면 필드 경계를 표현하는 데 도움이 된다. 그러나 내부 따옴표 처리와 실제 구분자·줄바꿈 계약도 맞아야 한다. 머리글·열 대응·값의 의미와 소비 앱의 수식 해석까지 보장하지는 않는다.

줄 수로 가져온 문의 건수를 세어도 되나요?

필드 안 줄바꿈이 있으면 맞지 않는다. CSV 파서가 반환한 레코드 중 머리글을 제외한 데이터 레코드를 세고, 빈 레코드를 어떻게 처리할지도 정한다. 이 예제에서는 네 물리 줄이 데이터 두 건을 표현했다.

다시 CSV로 썼을 때 바이트까지 같아야 하나요?

따옴표를 붙이는 방식이나 줄바꿈이 달라도 같은 필드 값을 표현할 수 있다. 업무가 원본 바이트 보존을 요구하는지, 파싱한 값의 보존을 요구하는지 나누어 검사한다. 이 글의 로컬 확인은 합성 입력의 필드 값 왕복 일치이며 모든 소비자의 호환성 인증은 아니다.

이 카테고리의 다른 글

전체글 보기

“CSV 쉼표·따옴표·줄바꿈, split으로 읽으면 왜 열이 틀어질까”에 대한 2개의 생각

댓글 남기기