파일 읽기에서 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