R:数据框中的重音字符

时间:2017-09-10 03:39:18

标签: r dataframe character-encoding

我很困惑为什么某些字符(例如“Ě”,“Č”和“ŝ”)在数据框中丢失了变音标记,而其他字符(例如“Š”和“š”)则没有。顺便说一句,我的操作系统是Windows 10。在下面的示例代码中,矢量czechvec有11个单字符字符串,都是斯拉夫语重音字符。 R正确显示这些字符。然后使用czechvec创建数据框mydf作为第二列(使用函数I(),因此它不会转换为因子)。但是当R显示mydf或任何一行mydf时,它会将大多数这些字符转换为它们的plain-ascii等价物;例如mydf [3,]将字符显示为“E”而不是“Ě”。但是使用行和列进行下标,例如mydf [3,2],它正确显示重音字符(“Ě”)。为什么R显示整行还是只显示一个单元格会有所不同?为什么像“Š”这样的角色完全不受影响?此外,当我将此数据帧写入文件时,它完全失去了重音,即使我指定fileEncoding =“UTF-8”。

> charvals <- c(193, 269, 282, 268, 262, 263, 348, 349, 350, 352, 353)
> hexvals  <- as.hexmode(charvals)
> czechvec <- unlist(strsplit(intToUtf8(charvals), ""))
> czechvec
[1] "Á" "č" "Ě" "Č" "Ć" "ć" "Ŝ" "ŝ" "Ş" "Š" "š"
> 
> mydf = data.frame(dec=charvals, char=I(czechvec), hex=I(format(hexvals, width=4, upper.case=TRUE)))
> mydf
   dec char  hex
1  193    Á 00C1
2  269    c 010D
3  282    E 011A
4  268    C 010C
5  262    C 0106
6  263    c 0107
7  348    S 015C
8  349    s 015D
9  350    S 015E
10 352    Š 0160
11 353    š 0161
> mydf[3,2]
[1] "Ě"
> mydf[3,]
  dec char  hex
3 282    E 011A
> 
> write.table(mydf, file="myfile.txt", fileEncoding="UTF-8")
> 
> df2 <- read.table("myfile.txt", stringsAsFactors=FALSE, fileEncoding="UTF-8")
> df2[3,2]
[1] "E"

编辑添加:Per Ernest A的答案,这种行为在Linux中无法重现。它必须是Windows问题。 (我正在使用R 3.4.1 for Windows。)

3 个答案:

答案 0 :(得分:1)

我无法使用R版本3.3.3(Linux)重现此行为。

> data.frame(dec=charvals, char=I(czechvec), hex=I(format(hexvals, width=4, upper.case=TRUE)))
   dec char  hex
1  193    Á 00C1
2  269    č 010D
3  282    Ě 011A
4  268    Č 010C
5  262    Ć 0106
6  263    ć 0107
7  348    Ŝ 015C
8  349    ŝ 015D
9  350    Ş 015E
10 352    Š 0160
11 353    š 0161

答案 1 :(得分:0)

感谢Ernest A的回答检查我观察到的奇怪行为在Linux中没有发生,我用Google搜索R WINDOWS UTF-8 BUG让我看到了Ista Zahn撰写的这篇文章:Escaping from character encoding hell in R on Windows

文章确认Windows上的data.frame打印方法存在错误,并提供了一些解决方法。 (但是,对于带有外语文本的数据框,本文没有注意到Windows中write.table的问题。)

Zahn提出的一个解决方法是更改​​区域设置以适应我们正在使用的特定语言:

Sys.setlocale(category = "LC_CTYPE", locale = "czech")
charvals <- c(193, 269, 282, 268, 262, 263, 348, 349, 350, 352, 353)
hexvals  <- format(as.hexmode(charvals), width=4, upper.case=TRUE)
df1      <- data.frame(dec=charvals, char=I(unlist(strsplit(intToUtf8(charvals), ""))), hex=I(hexvals))

print.listof(df1)

dec :
 [1] 193 269 282 268 262 263 348 349 350 352 353

char :
 [1] "Á" "č" "Ě" "Č" "Ć" "ć" "Ŝ" "ŝ" "Ş" "Š" "š"

hex :
 [1] "00C1" "010D" "011A" "010C" "0106" "0107" "015C" "015D" "015E" "0160"
[11] "0161"

df1
   dec char  hex
1  193    Á 00C1
2  269    č 010D
3  282    Ě 011A
4  268    Č 010C
5  262    Ć 0106
6  263    ć 0107
7  348    S 015C
8  349    s 015D
9  350    Ş 015E
10 352    Š 0160
11 353    š 0161

请注意捷克语字符现在正确显示但不是“Ŝ”和“ŝ”,Unicode U + 015C和U + 015D,显然在世界语中使用。但是使用print.listof命令,可以正确显示所有字符。 (顺便说一句,dput(df1)错误地列出了世界语字符,如“S”和“s”。)

write.table(df1, file="special characters example.txt", fileEncoding="UTF-8")
df2 <- read.table("special characters example.txt", stringsAsFactors=FALSE, fileEncoding="UTF-8")

print.listof(df2)
dec :
 [1] 193 269 282 268 262 263 348 349 350 352 353

char :
 [1] "Á" "č" "Ě" "Č" "Ć" "ć" "S" "s" "Ş" "Š" "š"

hex :
 [1] "00C1" "010D" "011A" "010C" "0106" "0107" "015C" "015D" "015E" "0160"
[11] "0161"

当我write.table df1然后read.table它返回为df2时,“Ŝ”和“ŝ”字符已经失去了它们的抑扬。这必须是write.table命令的问题,当我使用其他应用程序(如OpenOffice Writer)打开文件时确认。捷克字符都正确,但“Ŝ”和“ŝ”已更改为“S”和“s”。

目前,我的最佳解决方法是,不是将实际字符放在我的数据框中,而是记录它的Unicode值,然后使用write.table,并在OpenOffice中使用UNICHAR函数Calc将字符本身添加到文件中。但这很不方便。

我相信这个错误与此问题相关:how to read data in utf-8 format in R?

编辑添加:我现在在Stack Overflow上发现的其他类似问题:

Why do some Unicode characters display in matrices, but not data frames in R?

UTF-8 file output in R

Write UTF-8 files from R

我在这里找到了Peter Meissner对显示问题的解决方法:

http://r.789695.n4.nabble.com/Unicode-display-problem-with-data-frames-under-Windows-tp4707639p4707667.html

它涉及定义您自己的类unicode_df和打印函数print.unicode_df

这仍然无法解决我使用write.table将我的数据框(包含一些带有各种欧洲语言的文本的列)写入可以导入电子表格或任何文件的文件的问题。任意申请。但也许迈斯纳的解决方案可以适用于write.table

答案 2 :(得分:0)

这是一个函数write.unicode.csv,它使用pastewriteLines(带useBytes=TRUE)来导出包含外语字符的数据框(以UTF编码) 8)到csv文件。数据框中的所有单元格都将包含在csv文件中的引号中。

#function that will create a CSV file for a data frame containing Unicode text
#this can be used instead of write.csv in R for Windows
#source: https://stackoverflow.com/questions/46137078/r-accented-characters-in-data-frame
#this is not elegant, and probably not robust

write.unicode.csv <- function(mydf, filename="") {  #mydf can be a data frame or a matrix
   linestowrite <- character( length = 1+nrow(mydf) )
   linestowrite[1] <- paste('"","', paste(colnames(mydf), collapse='","'), '"', sep="") #first line will have the column names
   if(nrow(mydf)<1 | ncol(mydf)<1) print("This is not going to work.")        #a bit of error checking
   for(k1 in 1:nrow(mydf)) {
     r <- paste('"', k1, '"', sep="") #each row will begin with the row number in quotes
     for(k2 in 1:ncol(mydf)) {r <- paste(r, paste('"', mydf[k1, k2], '"', sep=""), sep=",")}
     linestowrite[1+k1] <- r
     }
   writeLines(linestowrite, con=filename, useBytes=TRUE)
   } #end of function

Sys.setlocale(category = "LC_CTYPE", locale = "usa")
charvals <- c(193, 269, 282, 268, 262, 263, 348, 349, 350, 352, 353)
hexvals  <- format(as.hexmode(charvals), width=4, upper.case=TRUE)
df1      <- data.frame(dec=charvals, char=I(unlist(strsplit(intToUtf8(charvals), ""))), hex=I(hexvals))

print.listof(df1)

write.csv(df1, file="test1.csv")
write.csv(df1, file="test2.csv", fileEncoding="UTF-8")
write.unicode.csv(df1, filename="test3.csv")

dftest1 <- read.csv(file="test1.csv", encoding="UTF-8", colClasses="character")
dftest2 <- read.csv(file="test2.csv", encoding="UTF-8", colClasses="character")
dftest3 <- read.csv(file="test3.csv", encoding="UTF-8", colClasses="character")

print("CSV file written using write.csv with no fileEncoding parameter:")
print.listof(dftest1)

print('CSV file written using write.csv with fileEncoding="UTF-8":')
print.listof(dftest2)

print("CSV file written using write.unicode.csv:")
print.listof(dftest3)