Прочитать файл в R со смешанными кодировками
Я пытаюсь прочитать таблицы в R с HTML-страниц, которые в основном кодируются в UTF-8 (и объявляют <meta charset="utf-8">
), но имеют некоторые строки в некоторых других кодировках (я думаю, Windows-1252 или ISO 8859-1). Вот пример. Я хочу, чтобы все правильно декодировалось в кадр данных R. XML::readHTMLTable
принимает аргумент encoding
но не позволяет использовать несколько кодировок.
Итак, в R, как я могу попробовать несколько кодировок для каждой строки входного файла? В Python 3 я бы сделал что-то вроде:
with open('file', 'rb') as o:
for line in o:
try:
line = line.decode('UTF-8')
except UnicodeDecodeError:
line = line.decode('Windows-1252')
Ответы
Ответ 1
Кажется, что существуют библиотечные функции R для угадывания кодировок символов, такие как stringi::stri_enc_detect
, но, когда это возможно, возможно, лучше использовать более простой детерминированный метод, пытаясь установить фиксированный набор кодировок по порядку. Похоже, что лучший способ сделать это - воспользоваться тем, что когда iconv
не преобразует строку, он возвращает NA
.
linewise.decode = function(path)
sapply(readLines(path), USE.NAMES = F, function(line) {
if (validUTF8(line))
return(line)
l2 = iconv(line, "Windows-1252", "UTF-8")
if (!is.na(l2))
return(l2)
l2 = iconv(line, "Shift-JIS", "UTF-8")
if (!is.na(l2))
return(l2)
stop("Encoding not detected")
})
Если вы создаете тестовый файл с
$ python3 -c 'with open("inptest", "wb") as o: o.write(b"This line is ASCII\n" + "This line is UTF-8: I like π\n".encode("UTF-8") + "This line is Windows-1252: Müller\n".encode("Windows-1252") + "This line is Shift-JIS: ハローワールド\n".encode("Shift-JIS"))'
тогда linewise.decode("inptest")
действительно возвращает
[1] "This line is ASCII"
[2] "This line is UTF-8: I like π"
[3] "This line is Windows-1252: Müller"
[4] "This line is Shift-JIS: ハローワールド"
Чтобы использовать linewise.decode
с XML::readHTMLTable
, просто скажите что-то вроде XML::readHTMLTable(linewise.decode("http://example.com"))
.
Ответ 2
Попробуйте использовать rvest
для очистки страницы? Это прекрасно работает, по крайней мере, для общего примера, и если другие страницы имеют похожую структуру, это также не должно быть трудным.
library(rvest)
url <- "http://web.archive.org/web/20190603144739id_/http://api-ak.wunderground.com/weatherstation/ListStations.asp?selectedCountry=fr"
tab1 <- url %>% read_html() %>% html_table() %>% .[[1]]
head(tab1)
# Station ID Neighborhood City Station Type Site
#1 IABLIS6 La Beauce Ablis Oregon Scientific Professional Weather Center NA
#2 IACHUN1 Achun Achun other NA
#3 IAFA3 route de lava Afa Ambient Weather WS-1001-WiFi (Wireless) NA
#4 IAGDE14 Proche de la plage Agde Ambient Weather WS-1001-WiFi (Wireless) NA
#5 IAGDE16 Station Hervé Agde other NA
#6 IAIGONNA2 OLI'VERT PAYSAGE METEO Aigonnay other NA
Ответ 3
Вы можете попробовать с readr
(https://cran.r-project.org/web/packages/readr/readr.pdf):
library(readr)
lines = readLines("http://web.archive.org/web/20190603144739id_/http://api-ak.wunderground.com/weatherstation/ListStations.asp?selectedCountry=fr")
lconv <- function(l){enc <- guess_encoding(as.vector(c(l, '0'))); enc$encoding[1]}
lines = ifelse(validUTF8(lines), lines, iconv(lines, lconv(lines), "UTF-8"))
Затем вы можете использовать readHTMLTable
в lines
. Обратите внимание, что если в тексте есть явная кодировка, readHTMLTable
будет использовать эту кодировку независимо от того, readHTMLTable
вы предоставляете.
EDIT: Вникая в проблемы, я нашел stri_enc_toutf8
функцию в stringi
пакет, который упрощает все:
> library(stringi)
> lines = readLines("http://web.archive.org/web/20190603144739id_/http://api-ak.wunderground.com/weatherstation/ListStations.asp?selectedCountry=fr")
> validUTF8(lines[12576])
[1] FALSE
> lines <- stri_enc_toutf8(lines)
> validUTF8(lines[12576])
[1] TRUE