Перекодировка части текста в data.frame из utf8 в win1251 в R
Есть объект data в формате data.frame, который содержит столбцы с текстом в сочетании с другими данными, часть текста нормально отображается в UTF-8, часть текста кракозябрами в win-1251.
Например, столбец data$attribute_3 содержит 500000 строк в UTF-8 и 300000 в win-1251.
Нужно ту часть текста, которая в UTF-8 перезаписать в кодировке win-1251. Часть данных с кодировкой win-1251 не трогать.
Как определить кодировку текста в R, чтобы отделить одно от другого, не нашел вообще никаких указаний.
Data берется из файла, в котором уже часть текста в UTF-8 часть в win-1251, так что читать данные из файла с encoding=UTF-8 не вариант.
Проблема только в том, чтобы определить где в data кончаются неправильно прочитанные в кодировке UTF-8 символы, закодированные в win-1251, которые отображаются как кракозябры. Перекодировать не проблема.
(Encoding(data$attribute_3)) везде выдаёт UTF-8.
UPD: stringi::stri_enc_detect и stringi::stri_enc_detect2 определяют весь текст как UTF-8 с вероятностью 1.
Ответы (1 шт):
Например, столбец data$attribute_3 содержит 500000 строк в UTF-8 и 300000 в win-1251
дальше исхожу из предположения, что в одной строке кодировки не смешаны, и каждая строка представляет собой либо utf8, либо cp1251.
для определения строки в кодировке utf8 можно воспользоваться, например, функцией Encoding() из пакета base:
Encoding("строка")
#> [1] "UTF-8"
Encoding(iconv("строка", from="utf8", to="cp1251"))
#> [1] "unknown"
соответственно для перекодирования можно воспользоваться такой функцией:
перекодирование1 <- function(x){ifelse(Encoding(x)=="UTF-8",iconv(x,from="utf8",to="cp1251"),x)}
применение её к таблице:
d <- data.frame(s=c("строка1",iconv("строка2",to="cp1251")))
d
#> s
#> 1 строка1
#> 2 \xf1\xf2\xf0\xee\xea\xe02
даст нужный результат:
apply(d, 2, перекодирование1)
#> s
#> [1,] "\xf1\xf2\xf0\xee\xea\xe01"
#> [2,] "\xf1\xf2\xf0\xee\xea\xe02"
другой вариант основывается на соображении, что при попытке перекодирования из utf8 уже перекодированной в cp1251 строки мы получим NA:
iconv(iconv("строка", from="utf8", to="cp1251"), from="utf8", to="cp1251")
#> [1] NA
соответственно функция перекодирования может быть такой:
перекодирование2 <- function(x) {c<-iconv(x,from="utf8",to="cp1251");ifelse(is.na(c),x,c)}
apply(d, 2, перекодирование2)
#> s
#> [1,] "\xf1\xf2\xf0\xee\xea\xe01"
#> [2,] "\xf1\xf2\xf0\xee\xea\xe02"
обновление1. пример удачного перекодирования:
x <- iconv('сибирь', from='cp1251', to='utf8')
x
#> [1] "СЃРёР±РёСЂСЊ"
iconv(x, from='utf8', to='cp1251')
#> [1] "сибирь"
обновление2. для устранения последствий «двойного перекодирования», когда часть строк и так была в кодировке utf8, но к ним было применено преобразование cp1251→utf8, типа такого:
iconv("сибирь",to="utf8",from="cp1251")
#> [1] "СЃРёР±РёСЂСЊ"
а часть строк, которая изначально была в кодировке cp1251, была корректно преобразована, и в результате получился вот такой винегрет:
t <- data.frame(s=c('сибирь',iconv('сибирь',to='utf8',from='cp1251')))
t
#> s
#> 1 сибирь
#> 2 СЃРёР±РёСЂСЊ
можно применить вот такую функцию:
перекодирование3 <- function(x) {c<-iconv(iconv(x,from="utf8",to="cp1251"),from="utf8",to="cp1251");ifelse(is.na(c),x,iconv(x,from="utf8",to="cp1251"))}
apply(t, 2, перекодирование3)
#> s
#> [1,] "сибирь"
#> [2,] "сибирь"
Created on 2020-11-06 by the reprex package (v0.3.0)