본문 바로가기

Python

[Python] csv 처리하면서 삽질내역( feat. BOM...)

회사에서 간단한 프로그램 하나를 만들라는 업무가 생겨서 파이썬으로 개발 진행 중이었다.

 

요구사항 중에 csv 파일을 읽어서 안에 있는 데이터를 url 주소 중간에 삽입해서 요청하는 것이 있었다. 샘플 csv를 받아서 20개 정도로만 반복문을 돌리면서 url이 잘 생성이 되는지 확인하고 있었다. 그런데, 첫번째 생성되는 url만 이상한 문자열이 붙은 채로 요청이 되고 그러면서 오류가 발생하는 것이었다. csv 파일에서 read를 해서 뽑힌 첫번째 줄 string은 아무리 봐도 이상한 문자 등이 포함이 안되어 있는데, 생성된 url을 주소창에 입력해보면 해당 string 앞에 '%EF%BB%BF' 라는 것이 항상 붙어 있는 것이었다.

 

예를 들면 아래와 같이 나오는 것이다. (회사 보안 상 실제 테스트 하던 url을 넣을 수 없음.)

// 이렇게 나오겠지라고 생각했던 url
https://www.test.com/sample/details?uid=test1

// 근데 실제 요청 시에는 이런 식으로 요청이 날라감...
https://www.test.com/sample/details?uid=%EF%BB%BFtest1

 

쓰레기 값 등이 들어가는 것이 있는지 이리저리 검색해도 아니고, 인코딩은 중간만 저렇게 되는건 말도 안되는 것 같았다. 

그러다 저 요상한 문자열을 그대로 구글 검색을 해보니 자동완성으로 'ef bb bf in url' 이라고 있었다.

아래 블로그를 들어가보니 해당 문자가 File Signature 라는 것이었다.

http://forensic-proof.com/archives/300

출처 : http://forensic-proof.com/archives/300

파일 포맷 별로 구분을 위해서 파일 시작점에 고유 시그니쳐를 첫번째에 넣는 경우가 있다고 한다. 그래서 위와 같은 케이스가 생긴 것이었다.  저게 BOM이라는 것이었다. BOM은 눈에 보이지 않기 때문에 해당 표시가 있는지 없는지 구분을 할 수 가 없어서 이걸로 1시간 가까이 고생을 했다....


BOM 이란

바이트 순서 표시(Byte Order Mark, BOM)는 유니코드 문자 U+FEFF byte order mark로, 매직 넘버로서 문서의 가장 앞에 추가하여 텍스트를 읽는 프로그램에 여러 정보를 전달할 수 있다.[1]

  • 16비트 혹은 32비트 인코딩의 경우, 문서의 바이트 순서 또는 엔디언
  • 문서의 인코딩이 거의 확실히 유니코드임
  • 문서에 사용한 유니코드 문자 인코딩 방식

BOM을 반드시 사용할 필요는 없으며, 사용할 경우 문서의 가장 앞에 등장해야 한다.

유니코드는 8비트, 16비트 혹은 32비트 정수 단위로 인코딩할 수 있다. 16비트 및 32비트 표현의 경우, 알 수 없는 출처로부터 텍스트를 읽는 컴퓨터는 데이터를 어떤 바이트 순서로 인코딩했는지 알아야 한다. BOM은 문서의 나머지 부분과 같은 방식으로 인코딩되며 바이트 순서가 바뀔 경우 비문자인 유니코드 코드 포인트가 되므로, 이 텍스트를 읽는 프로세스는 문서 외적인 정보 없이도 처음 몇 바이트를 검사함으로써 엔디언을 확인할 수 있다. 이후 수신자는 필요할 경우 바이트 순서를 자신의 엔디안에 맞게 바꾸며, 이 이후의 처리에는 더 이상 BOM이 필요하지 않다.

BOM의 바이트열은 유니코드 인코딩마다 다르며, 이들이 다른 인코딩으로 저장된 문서의 가장 앞에 등장할 가능성은 적다. 그러므로, 문서의 가장 앞에 인코딩된 BOM을 추가함으로써 텍스트가 유니코드임을 나타내고 그 인코딩 방식을 명시할 수 있다. BOM 문자를 이 방식으로 사용하는 것을 "유니코드 시그니처"라 한다.

 

(출처 : 위키백과)


 

원인을 알아냈으니 이제 해결책을 찾아보자. 답은 csv 파일을 읽을 때 encoding을 변경하면 되는 것이었다.

# 기존 코드
csv_file = open(path, 'r', encoding='utf-8')

# 변경된 코드
csv_file = open(path, 'r', encoding='utf-8-sig')

 

utf-8의 경우에는 BOM이 포함이 되며, utf-8-sig는 BOM이 포함되지 않는다.

python에서 csv 파일을 읽고 쓸 때 되도록이면 utf-8-sig를 사용해야 편할 것 같다..

 

오늘 삽질 내역 정리 끝!!