파일 읽기에서 BOM(Byte Order Marks)
첨부파일: 서울시 한강공원 이용객 현황 (2009_2013년).csv
책에는 BOM에 대해 자세하게 설명하였습니다.
UTF-8-BOM의 경우 Notepad++에서 인코딩을 확인할 수 있습니다만,
또 뭐 굳이 그것때문에 Notepad++를 다운로드 받아 설치할 필요가… 없긴 합니다만,
또 막상 인터넷 검색을 해보면 다른 방법이 쉽게 떠오르지 않네요.
그래서 만들어봤습니다. R에서 BOM 존재를 확인하는 방법, 그리고 파일을 읽는 방법을 제안합니다.
# BOM 또는 UTF8-Signature 확인 방법 f <- file("서울시 한강공원 이용객 현황 (2009_2013년).csv", "rb") marks <- readBin(f, "raw", n=10) # 출처: https://en.wikipedia.org/wiki/Byte_order_mark BOM_UTF8 <- as.raw(c(0xef, 0xbb, 0xbf)) BOM_UTF16BE <- as.raw(c(0xfe, 0xff)) BOM_UTF16LE <- as.raw(c(0xff, 0xfe)) BOM_UTF32BE <- as.raw(c(0x00, 0x00, 0xfe, 0xff)) BOM_UTF32LE <- as.raw(c(0xff, 0xfe, 0x00, 0x00)) BOM_UTF7 <- as.raw(c(0x2b, 0x2f, 0x76)) BOM_UTF1 <- as.raw(c(0xf7, 0x64, 0x4c)) BOM_UTF_EBCDIC <- as.raw(c(0xdd, 0x73, 0x66, 0x73)) BOM_SCSU <- as.raw(c(0x0e, 0xfe, 0xff)) BOM_BOCU1 <- as.raw(c(0xfb, 0xee, 0x28)) BOM_GB18030 <- as.raw(c(0x84, 0x31, 0x95, 0x33)) BOMs = list("UTF8"=BOM_UTF8, "UTF16BE"=BOM_UTF16BE, "UTF16LE"=BOM_UTF16LE, "UTF32BE"=BOM_UTF32BE, "UTF32LE"=BOM_UTF32LE, "UTF7"=BOM_UTF7, "UTF1"=BOM_UTF1, "UTF-EBCDIC"=BOM_UTF_EBCDIC, "SCSU"=BOM_SCSU, "BOCU-1"=BOM_BOCU1, "GB-18030"=BOM_GB18030) check_marks = function(BOM) { if (all(marks[1:length(BOM)] == BOM)) return(TRUE) else return(FALSE) } names(BOMs)[sapply(BOMs, check_marks)] # UTF8
첨부파일 “서울시 한강공원 이용객 현황 (2009_2013년).csv”는 인코딩이 UTF-8-BOM 또는 UTF-8-Signature입니다(첫 글자가 유니코드 0xfeff이죠). 위의 코드는 파일의 첫 부분을 읽어서 BOM과 비교해서 인코딩을 확인하죠. 만약 BOM이 없다면 없다고 나옵니다.
이제 함수로 만들어봅니다.
# ==== # 함수로 만들기 # checkBOM(filename) checkBOM = function(filename) { marks <- readBin(filename, "raw", n=4) BOM_UTF8 <- as.raw(c(0xef, 0xbb, 0xbf)) BOM_UTF16BE <- as.raw(c(0xfe, 0xff)) BOM_UTF16LE <- as.raw(c(0xff, 0xfe)) BOM_UTF32BE <- as.raw(c(0x00, 0x00, 0xfe, 0xff)) BOM_UTF32LE <- as.raw(c(0xff, 0xfe, 0x00, 0x00)) BOM_UTF7 <- as.raw(c(0x2b, 0x2f, 0x76)) BOM_UTF1 <- as.raw(c(0xf7, 0x64, 0x4c)) BOM_UTF_EBCDIC <- as.raw(c(0xdd, 0x73, 0x66, 0x73)) BOM_SCSU <- as.raw(c(0x0e, 0xfe, 0xff)) BOM_BOCU1 <- as.raw(c(0xfb, 0xee, 0x28)) BOM_GB18030 <- as.raw(c(0x84, 0x31, 0x95, 0x33)) BOMs = list("UTF8"=BOM_UTF8, "UTF16BE"=BOM_UTF16BE, "UTF16LE"=BOM_UTF16LE, "UTF32BE"=BOM_UTF32BE, "UTF32LE"=BOM_UTF32LE, "UTF7"=BOM_UTF7, "UTF1"=BOM_UTF1, "UTF-EBCDIC"=BOM_UTF_EBCDIC, "SCSU"=BOM_SCSU, "BOCU-1"=BOM_BOCU1, "GB-18030"=BOM_GB18030) check_marks = function(BOM) { if (all(marks[1:length(BOM)] == BOM)) return(TRUE) else return(FALSE) } res = names(BOMs)[sapply(BOMs, check_marks)] if (length(res)>0) { con = file(filename, "rb") readBin(con, "raw", n = length(BOMs[[res]])) return(list(BOM=res, con=con)) } else { return(list(BOM="", con=file(filename), "rb")) } }
문제: 위의 함수를 어떻게 써야 할까요? (힌트 : checkBOM(filename))
## 참고자료
* https://stackoverflow.com/questions/39593637/dealing-with-byte-order-mark-bom-in-r
* https://118k.tistory.com/863
* https://github.com/tidyverse/readr/issues/500
– readr은 BOM을 해결한 걸로 아는데 지금 다시 locale(encoding = “UTF-8-BOM”) 해보니 여전히 못 읽고 있네요.
참고도서> R로 하는 빅데이터 분석: 데이터 전처리와 시각화
Leave a comment