在 R 中从列表转换为 data.frame 时,utf-8 字符会丢失

utf-8 characters get lost when converting from list to data.frame in R

我在 Windows 7 64 位上使用 R 3.2.0 和 RStudio 0.98.1103。我电脑的Windows"regional and language settings"是英文(美国)

出于某种原因,当我阅读 [=26] 时,以下代码将文本 "Koryčany nad přehradou" 中的捷克语字符“č”和“ř”替换为 "c" 和 "r" =] 从网络上以 utf-8 编码的文件,将 XML 文件解析为列表,并将列表转换为 data.frame.

library(XML)
url <- "http://hydrodata.info/chmi-h/cuahsi_1_1.asmx/GetSiteInfoObject?site=CHMI-H:1263&authToken="
doc <- xmlRoot(xmlTreeParse(url, getDTD=FALSE, useInternalNodes = TRUE))
infoList <- xmlToList(doc[[2]][[1]])
siteName <- infoList$siteName

#this still displays correctly "Koryčany nad přehradou"
print(siteName) 

#make a data.frame from the list item. I suspect here is the problem.
df <- data.frame(name=siteName, id=1)

#now the Czech characters are lost. I see only "Korycany nad prehradou"
View(df) 

write.csv(df,"test.csv")
#the test.csv file also contains "Korycany nad prehradou" 
#instead of "Koryčany nad přehradou"

问题是什么?如何使 R 正确显示所有 utf-8 特殊字符的 data.frame 并保存 .csv 文件而不丢失“č”和“ř”捷克字符?

这不是一个完美的答案,但以下解决方法解决了我的问题。我试图理解 R 的行为,并制作示例,以便我的 R 脚本在 Windows 和 Linux 平台上产生相同的结果:

(1) 从网上获取XML UTF-8 格式的数据

library(XML)
url <- "http://hydrodata.info/chmi-h/cuahsi_1_1.asmx/GetSiteInfoObject?site=CHMI-H:1263&authToken="
doc <- xmlRoot(xmlTreeParse(url, getDTD=FALSE, useInternalNodes = TRUE))
infoList <- xmlToList(doc[[2]][[1]])
siteName <- infoList$siteName

(2) 打印出网上的文字:编码为UTF-8,在Windows上使用捷克语和英语语言环境在R控制台中显示也是正确的:

> Sys.getlocale(category="LC_CTYPE")
[1] "English_United States.1252"
> print(siteName)
[1] "Koryčany nad přehradou"
> Encoding(siteName)
[1] "UTF-8"
> 

(3) 尝试创建和查看 data.frame。这有问题。 data.frame 在 RStudio 视图和控制台中均显示不正确:

df <- data.frame(name=siteName, id=1)
df
                    name id
1 Korycany nad prehradou  1

(4) 尝试使用矩阵代替。令人惊讶的是矩阵在 R 控制台中正确显示。

m <- as.matrix(df)
View(m)  #this shows incorrectly in RStudio
m        #however, this shows correctly in the R console.
     name                     id 
[1,] "Koryčany nad přehradou" "1"

(5) 更改语言环境。如果我在 Windows,请将语言环境设置为捷克语。如果我在 Unix 或 Mac 上,请将语言环境设置为 UTF-8。注意:当我 运行 RStudio 中的脚本时,这有一些问题,显然 RStudio 并不总是立即对 Sys.setlocale 命令做出反应。

#remember the original locale.
original.locale <- Sys.getlocale(category="LC_CTYPE")

#for Windows set locale to Czech. Otherwise set locale to UTF-8
new.locale <- ifelse(.Platform$OS.type=="windows", "Czech_Czech Republic.1250", "en_US.UTF-8")
Sys.setlocale("LC_CTYPE", new.locale) 

(7) 将数据写入文本文件。重要提示:不要使用 write.csv,而是使用 write.table。当我的语言环境是 Czech 而我的英语 Windows 时,我必须在 write.table 中使用 fileEncoding="UTF-8"。现在文本文件在 notepad++ 和 Excel.

中正确显示
write.table(m, "test-czech-utf8.txt", sep="\t", fileEncoding="UTF-8")

(8) 将语言环境设置回原来的

Sys.setlocale("LC_CTYPE", original.locale)

(9) 尝试将文本文件读回 R。注意:如果我读取文件,我必须设置 encoding 参数(不是 fileEncoding!)。从文件中读取的 data.frame 的显示仍然不正确,但是当我将我的 data.frame 转换为 matrix 时,捷克语 UTF-8 字符被保留:

data.from.file <- read.table("test-czech-utf8.txt", sep="\t", encoding="UTF-8")
#the data.frame still has the display problem, "č" and "ř" get "lost"
> data.from.file
                     name id
1 Korycany nad prehradou  1

#see if a matrix displays correctly: YES it does!
matrix.from.file <- as.matrix(data.from.file)
> matrix.from.file
  name                     id 
1 "Koryčany nad přehradou" "1"

所以吸取的教训是我需要将我的 data.frame 转换为 matrix,将我的语言环境设置为 Czech(在 Windows 上)或 UTF-8(在 Mac 和 Linux 上),然后我将带有捷克语字符的数据写入文件。然后当我写文件时,我必须确保 fileEncoding 必须设置为 UTF-8。另一方面,当我稍后阅读该文件时,我可以继续在英语语言环境中工作,但在 read.table 中我必须设置 encoding="UTF-8"

如果有人有更好的解决方案,欢迎提出建议。