2011-03-10 15 views
10

Tengo problemas para generar un data.frame utilizando write.csv usando la codificación de caracteres UTF-16.R write.csv con codificación UTF-16

Antecedentes: Estoy tratando de escribir un archivo CSV a partir de un data.frame para su uso en Excel. A Excel Mac 2011 parece no gustarle UTF-8 (si especifico UTF-8 durante la importación de texto, los caracteres que no son ASCII aparecen como guiones bajos). Me han hecho creer que Excel estará contento con la codificación UTF-16LE.

Aquí está el ejemplo hoja.de.datos:

> foo 
    a b 
1 á 羽 
> Encoding(levels(foo$a)) 
[1] "UTF-8" 
> Encoding(levels(foo$b)) 
[1] "UTF-8" 

así que traté de salida de la hoja.de.datos haciendo:

f <- file("foo.csv", encoding="UTF-16LE") 
write.csv(foo, f) 

Esto me da un archivo ASCII que se parece a:

""," 

Si uso encoding="UTF-16", obtengo un archivo que solo contiene la marca de orden de bytes 0xFE 0xFF.

Si uso encoding="UTF-16BE", obtengo un archivo vacío.

Esto está en una versión de 64 bits de R 2.12.2 en Mac OS X 10.6.6. ¿Qué estoy haciendo mal?

+2

Para el registro, WTF está mal con Excel y UTF-8? Quiero decir, vamos, es 2011. –

Respuesta

6

Usted podría simplemente guardar el csv en UTF-8 y posteriormente convertirla en UTF-16LE con iconv en el terminal.

Si insiste en hacerlo en R, el siguiente podría funcionar - aunque incluya parece que iconv en I tiene algunos problemas, ver: http://tolstoy.newcastle.edu.au/R/e10/devel/10/06/0648.html

> x <- c("foo", "bar") 
> iconv(x,"UTF-8","UTF-16LE") 
Error in iconv(x, "UTF-8", "UTF-16LE") : 
    embedded nul in string: 'f\0o\0o\0' 

Como se puede ver el parche vinculado anteriormente es realmente necesario, que no probé, pero si desea mantenerlo simulado (y desagradable): simplemente llame al programa iconv de terceros dentro de R con una llamada system después de guardar la tabla en csv.

+0

He estado usando iconv después de sacar el UTF-8, pero esperaba que estuviera haciendo algo mal y que con gusto sacaría UTF-16 directamente. Supongo que puede no ser el caso ... –

+1

@Daniel Dickison: parece que sí :(Si puedo, sugiero que llame a iconv desde R después de guardar el marco de datos, solo use la función 'system' - de esta manera no tendrá que iniciar un programa por separado. También puede automatizar el proceso escribiendo una pequeña función que guarda el * csv * y también convierte a la codificación deseada. ¡Buena suerte! – daroczig

+1

¿Por qué el ícono de UTF-16 todavía no arreglado en R (el parche está fechado en 2010)? Todavía no veo una manera fácil de "nativa" en R de leer o escribir archivos de texto codificados en UTF-16 (Windows) en 2016 :-( –

4

algo así podría hacer (write.csv() simplemente ignora la codificación por lo que tiene que optar por writLines() o writeBin()) ...

#' function to convert character vectors to UTF-8 encoding 
#' 
#' @param x the vector to be converted 
#' @export 

toUTF8 <- 
    function(x){ 
    worker <- function(x){ 
     iconv(x, from = Encoding(x), to = "UTF-8") 
    } 
    unlist(lapply(x, worker)) 
    } 



#' function to write csv files with UTF-8 characters (even under Windwos) 
#' @param df data frame to be written to file 
#' @param file file name/path where to put the data 
#' @export 

write_utf8_csv <- 
function(df, file){ 
    firstline <- paste( '"', names(df), '"', sep = "", collapse = " , ") 
    char_columns <- seq_along(df[1,])[sapply(df, class)=="character"] 
    for(i in char_columns){ 
    df[,i] <- toUTF8(df[,i]) 
    } 
    data <- apply(df, 1, function(x){paste('"', x,'"', sep = "",collapse = " , ")}) 
    writeLines(c(firstline, data), file , useBytes = T) 
} 


#' function to read csv file with UTF-8 characters (even under Windwos) that 
#' were created by write_U 
#' @param df data frame to be written to file 
#' @param file file name/path where to put the data 
#' @export 

read_utf8_csv <- function(file){ 
    # reading data from file 
    content <- readLines(file, encoding = "UTF-8") 
    # extracting data 
    content <- stringr::str_split(content, " , ") 
    content <- lapply(content, stringr::str_replace_all, '"', "") 
    content_names <- content[[1]][content[[1]]!=""] 
    content <- content[seq_along(content)[-1]] 
    # putting it into data.frame 
    df <- data.frame(dummy=seq_along(content), stringsAsFactors = F) 
    for(name in content_names){ 
    tmp <- sapply(content, `[[`, dim(df)[2]) 
    Encoding(tmp) <- "UTF-8" 
    df[,name] <- tmp 
    } 
    df <- df[,-1] 
    # return 
    return(df) 
} 
Cuestiones relacionadas