2017-09-10 62 views
3

我對某些字符(例如「Ě」,「Č」和「ŝ」)在數據幀中失去其變音符號感到困惑,而其他字符(例如「Š」和「 「š」)不。順便說一句,我的操作系統是Windows 10。在下面的示例代碼中,矢量czechvec有11個單字符字符串,都是斯拉夫重音字符。 R正確顯示這些字符。然後用czechvec作爲第二列創建一個數據幀mydf(函數I()被使用,所以它不會被轉換爲一個因子)。但是當R顯示mydf或mydf的任何一行時,它會將這些字符中的大部分轉換爲它們的plain-ascii等效值;例如mydf [3,]將字符顯示爲「E」而不是「Ě」。但是使用行和列下標,例如mydf [3,2],它能正確顯示重音字符(「Ě」)。爲什麼R顯示整行或只顯示一個單元格會有所影響?爲什麼像「Š」這樣的字符完全不受影響?同樣,當我將這個數據框寫入文件時,即使指定了fileEncoding =「UTF-8」,它也完全失去了重音。R:數據幀中帶重音符號

> 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。)

回答

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 
0

由於歐內斯特·A的答案覈對,我觀察到在Linux中不會出現怪異的行爲,我Google R WINDOWS UTF-8 BUG這使我這個文章土改贊恩:Escaping from character encoding hell in R on Windows

文章確認有一個bug在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 

注意,捷克字符現在正確地但不是「s」和「S」,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中,「S」和「S」字符已經失去了他們的旋律。這一定是write.table命令的一個問題,正如我用另一個應用程序(如OpenOffice Writer)打開文件時所證實的那樣。捷克字符都正確,但「Ŝ」和「ŝ」已被更改爲「S」和「S」。

對於我而言,目前最好的解決方法是,不是將實際字符放在我的數據框中,而是記錄它的Unicode值,然後使用write.table,並使用OpenOffice Calc中的UNICHAR函數添加字符本身的文件。但這很不方便。

我相信這同樣的錯誤是有關這個問題:how to read data in utf-8 format in R?

編輯補充:

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

我找到了解決方法顯示問題由彼得·邁斯納在這裏:

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

0

下面是一個使用pastewriteLines(與useBytes=TRUE)到導出包含外文字符的數據幀(以UTF-8編碼)到csv文件中的函數write.unicode.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)