我很困惑为什么某些字符(例如“Ě”,“Č”和“ŝ”)在数据框中丢失了变音标记,而其他字符(例如“Š”和“š”)则没有。顺便说一句,我的操作系统是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。)
答案 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?
我在这里找到了Peter Meissner对显示问题的解决方法:
它涉及定义您自己的类unicode_df
和打印函数print.unicode_df
。
这仍然无法解决我使用write.table
将我的数据框(包含一些带有各种欧洲语言的文本的列)写入可以导入电子表格或任何文件的文件的问题。任意申请。但也许迈斯纳的解决方案可以适用于write.table
。
答案 2 :(得分:0)
这是一个函数write.unicode.csv,它使用paste
和writeLines
(带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)