在 R 中希伯来语编码地狱并在 Windows 中编写 UTF-8 table
Hebrew Encoding Hell in R and writing a UTF-8 table in Windows
我正在尝试保存使用 RSelenium
从 https://www.magna.isa.gov.il/Details.aspx?l=he 中提取的数据,但是尽管 R 成功地将希伯来语字符打印到控制台,但在导出 TXT、CSV 或其他简单的 R 时却没有函数,例如 data.frame()
、readHTMLTable()
等
举个例子。
> head(lines)
[1] "גלובל פיננס ג'י.אר. 2 בע\"מ נתונים כספיים באלפי דולר ארה\"ב"
[2] "513435404"
[3] ""
[4] ""
[5] ""
[6] "4,481"
当使用 data.frame()
时,第一行变为奇怪的字符(下)
> head(as.data.frame(lines))
[1] <U+05D2><U+05DC><U+05D5><U+05D1><U+05DC> <U+05E4><U+05D9><U+05E0><U+05E0><U+05E1> <U+05D2>'<U+05D9>.<U+05D0><U+05E8>. 2 <U+05D1><U+05E2>"<U+05DE> <U+05E0><U+05EA><U+05D5><U+05E0><U+05D9><U+05DD> <U+05DB><U+05E1><U+05E4><U+05D9><U+05D9><U+05DD> <U+05D1><U+05D0><U+05DC><U+05E4><U+05D9> <U+05D3><U+05D5><U+05DC><U+05E8> <U+05D0><U+05E8><U+05D4>"<U+05D1>
通过 write.table
或 write.csv
:
导出 .TXT 或 .CSV 时也会发生同样的情况
write.csv(lines,"lines.csv",row.names=FALSE)
我尝试将编码更改为 "UTF-8",就像几个类似问题中的建议一样,但问题仍然存在于不同的格式中:
iconv(lines, to = "UTF-8")
1 ׳’׳׳•׳‘׳ ׳₪׳™׳ ׳ ׳¡ ׳’'׳™.׳׳¨. 2 ׳‘׳¢"׳ ׳ ׳×׳•׳ ׳™׳ ׳›׳¡׳₪׳™׳™׳ ׳‘׳׳׳₪׳™ ׳“׳•׳׳¨ ׳׳¨׳”"׳‘
希伯来语 ISO-8859-8 相同:
iconv(lines, to = "ISO-8859-8")
1 ×'×o×.×'×o ×₪×T× × ×! ×''×T.×ר. 2 ×'×¢"×z × ×a×.× ×T× ×>×!×₪×T×T× ×'××o×₪×T ×"×.×oר ×ר×""×'
我不明白为什么控制台可以很好地打印希伯来字符,而 write.table()
、write.csv()
和 data.frame()
却出现编码问题。
有人帮我导出吗?
That was answered by Ken, exporting text with writeLines() worked well:
f = file("lines.txt", open = "wt", encoding = "UTF-8")
writeLines(lines, "lines.txt", useBytes = TRUE)
close(f)
然而,主要问题 R 使用希伯来语编码是,而处理表 , 形式为 as.data.frame(), write.table() 和 write.csv()。有什么想法吗?
一些机器信息:
Sys.info()
sysname release version
"Windows" "7 x64" "build 7601, Service Pack 1"
nodename machine login
"TALIS-TP" "x86"
> Sys.getlocale()
[1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"
许多人在具有 8 位系统编码 (Windows) 的平台上使用 UTF-8 文本时遇到类似的问题。 R 中的编码可能很棘手,因为不同的方法处理编码和转换的方式不同,并且在一个平台(OS X 或 Linux)上看起来工作正常的东西在另一个平台上工作不佳。
问题与您的输出连接以及 Windows 如何处理编码和文本连接有关。我尝试使用 UTF-8 和 8 位编码中的一些希伯来语文本来复制该问题。我们还将介绍文件读取问题,因为那里也可能存在一些问题。
用于测试
创建了一个简短的希伯来语文本文件,编码为 UTF-8:hebrew-utf8.txt
创建了一个简短的希伯来语文本文件,编码为 ISO-8859-8:hebrew-iso-8859-8.txt。 (注意:您可能需要告诉浏览器有关编码的信息才能正确查看此编码 - 例如 Safari 就是这种情况。)
读取文件的方法
现在让我们来试验一下。我正在使用 Windows 7 进行这些测试(它实际上适用于 OS X,我通常使用 OS)。
lines <- readLines("http://kenbenoit.net/files/hebrew-utf8.txt")
lines
## [1] "העברי ×”×•× ×—×‘×¨ בקבוצה ×”×›× ×¢× ×™×ª של שפות שמיות."
## [2] "זו היתה ×©×¤×ª× ×©×œ ×”×™×”×•×“×™× ×ž×•×§×“×, ×בל מן 586 ×œ×¤× ×”\"ס ×–×” התחיל להיות מוחלף על ידי ב×רמית."
失败,因为它假定编码是您的系统编码,Windows-1252。但是因为当你读取文件时没有发生转换,你可以通过将编码位设置为 UTF-8 来解决这个问题:
# this sets the bit for UTF-8
Encoding(lines) <- "UTF-8"
lines
## [1] "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
## [2] "זו היתה שפתם של היהודים מוקדם, אבל מן 586 לפנה\"ס זה התחיל להיות מוחלף על ידי בארמית."
但最好在阅读文件时执行此操作:
# this does it in one pass
lines2 <- readLines("http://kenbenoit.net/files/hebrew-utf8.txt", encoding = "UTF-8")
lines2[1]
## [1] "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
Encoding(lines2)
## [1] "UTF-8" "UTF-8"
现在看看如果我们尝试读取相同的文本但编码为 8 位 ISO 希伯来语代码页会发生什么。
lines3 <- readLines("http://kenbenoit.net/files/hebrew-iso-8859-8.txt")
lines3[1]
## [1] "äòáøé äåà çáø á÷áåöä äëðòðéú ùì ùôåú ùîéåú."
设置编码位在这里没有帮助,因为读取的内容没有映射到希伯来语的 Unicode 代码点,并且 Encoding()
没有实际编码转换,它只是设置了一个额外的位可以用于告诉 R 几个可能的编码值之一。我们可以通过将 encoding = "ISO-8859-8"
添加到 readLines()
调用来解决这个问题。我们还可以在加载后转换文本,使用 iconv()
:
# this will not fix things
Encoding(lines3) <- "UTF-8"
lines3[1]
## [1] "\xe4\xf2\xe1\xf8\xe9 \xe4\xe5\xe0 \xe7\xe1\xf8 \xe1\xf7\xe1\xe5\xf6\xe4 \xe4\xeb\xf0\xf2\xf0\xe9\xfa \xf9\xec \xf9\xf4\xe5\xfa \xf9\xee\xe9\xe5\xfa."
# but this will
iconv(lines3, "ISO-8859-8", "UTF-8")[1]
## [1] "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
总的来说,我认为上面用于 lines2
的方法是最好的方法。
如何输出文件,保留编码
现在回答关于如何编写的问题:最安全的方法是在低级别控制您的连接,您可以在其中指定编码。否则,默认为 R/Windows 选择您的系统编码,这将丢失 UTF-8。我认为这行得通,在 OS X 上绝对没问题 - 在 OS X 上也能正常调用 writeLines()
只是命名文本没有 textConnection 的文件。
## to write lines, use the encoding option of a connection object
f <- file("hebrew-output-UTF-8.txt", open = "wt", encoding = "UTF-8")
writeLines(lines2, f)
close(f)
但它不适用于 Windows。您可以在此处查看 Windows 7 个结果:hebrew-output-UTF-8-file_encoding.txt.
所以,这是如何做到的 在 Windows 中:一旦您确定您的文本编码为 UTF-8,只需将其写为原始字节,不使用任何编码,像这样:
writeLines(lines2, "hebrew-output-UTF-8-useBytesTRUE.txt", useBytes = TRUE)
您可以在 hebrew-output-UTF-8-useBytesTRUE.txt 看到结果,现在是 UTF-8,看起来是正确的。
Added for write.csv
请注意,您想要执行此操作的唯一原因是使 .csv 文件可用于导入其他软件,例如 Excel。 (祝你在 Excel/Windows 中使用 UTF-8 好运...)否则,你应该使用 write(myDataFrame, file = "myDataFrame.RData")
将 data.table 编写为二进制文件。但是如果你真的需要输出.csv,那么:
如何从 Windows
中的 data.table
写入 UTF-8 .csv 文件
使用 write.table()
和 write.csv()
编写 UTF-8 文件的问题在于这些打开的文本连接,而 Windows 对 UTF- 8. (This post offers a helpful explanation.) Following from an SO answer posted here,我们可以覆盖它来编写我们自己的函数来输出 UTF-8 .csv 文件。
这假设您已经将任何字符元素的 Encoding()
设置为 "UTF-8"
(这发生在上面为 lines2
导入时)。
df <- data.frame(int = 1:2, text = lines2, stringsAsFactors = FALSE)
write_utf8_csv <- function(df, file) {
firstline <- paste('"', names(df), '"', sep = "", collapse = " , ")
data <- apply(df, 1, function(x) {paste('"', x, '"', sep = "", collapse = " , ")})
writeLines(c(firstline, data), file , useBytes = TRUE)
}
write_utf8_csv(df, "df_csv.txt")
当我们现在在非 Unicode 挑战 OS 中查看该文件时,它现在看起来很好:
KBsMBP15-2:Desktop kbenoit$ cat df_csv.txt
"int" , "text"
"1" , "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
"2" , "זו היתה שפתם של היהודים מוקדם, אבל מן 586 לפנה"ס זה התחיל להיות מוחלף על ידי בארמית."
KBsMBP15-2:Desktop kbenoit$ file df_csv.txt
df_csv.txt: UTF-8 Unicode text, with CRLF line terminators
我正在尝试保存使用 RSelenium
从 https://www.magna.isa.gov.il/Details.aspx?l=he 中提取的数据,但是尽管 R 成功地将希伯来语字符打印到控制台,但在导出 TXT、CSV 或其他简单的 R 时却没有函数,例如 data.frame()
、readHTMLTable()
等
举个例子。
> head(lines)
[1] "גלובל פיננס ג'י.אר. 2 בע\"מ נתונים כספיים באלפי דולר ארה\"ב"
[2] "513435404"
[3] ""
[4] ""
[5] ""
[6] "4,481"
当使用 data.frame()
> head(as.data.frame(lines))
[1] <U+05D2><U+05DC><U+05D5><U+05D1><U+05DC> <U+05E4><U+05D9><U+05E0><U+05E0><U+05E1> <U+05D2>'<U+05D9>.<U+05D0><U+05E8>. 2 <U+05D1><U+05E2>"<U+05DE> <U+05E0><U+05EA><U+05D5><U+05E0><U+05D9><U+05DD> <U+05DB><U+05E1><U+05E4><U+05D9><U+05D9><U+05DD> <U+05D1><U+05D0><U+05DC><U+05E4><U+05D9> <U+05D3><U+05D5><U+05DC><U+05E8> <U+05D0><U+05E8><U+05D4>"<U+05D1>
通过 write.table
或 write.csv
:
write.csv(lines,"lines.csv",row.names=FALSE)
我尝试将编码更改为 "UTF-8",就像几个类似问题中的建议一样,但问题仍然存在于不同的格式中:
iconv(lines, to = "UTF-8")
1 ׳’׳׳•׳‘׳ ׳₪׳™׳ ׳ ׳¡ ׳’'׳™.׳׳¨. 2 ׳‘׳¢"׳ ׳ ׳×׳•׳ ׳™׳ ׳›׳¡׳₪׳™׳™׳ ׳‘׳׳׳₪׳™ ׳“׳•׳׳¨ ׳׳¨׳”"׳‘
希伯来语 ISO-8859-8 相同:
iconv(lines, to = "ISO-8859-8")
1 ×'×o×.×'×o ×₪×T× × ×! ×''×T.×ר. 2 ×'×¢"×z × ×a×.× ×T× ×>×!×₪×T×T× ×'××o×₪×T ×"×.×oר ×ר×""×'
我不明白为什么控制台可以很好地打印希伯来字符,而 write.table()
、write.csv()
和 data.frame()
却出现编码问题。
有人帮我导出吗?
That was answered by Ken, exporting text with writeLines() worked well:
f = file("lines.txt", open = "wt", encoding = "UTF-8")
writeLines(lines, "lines.txt", useBytes = TRUE)
close(f)
然而,主要问题 R 使用希伯来语编码是,而处理表 , 形式为 as.data.frame(), write.table() 和 write.csv()。有什么想法吗?
一些机器信息:
Sys.info()
sysname release version
"Windows" "7 x64" "build 7601, Service Pack 1"
nodename machine login
"TALIS-TP" "x86"
> Sys.getlocale()
[1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"
许多人在具有 8 位系统编码 (Windows) 的平台上使用 UTF-8 文本时遇到类似的问题。 R 中的编码可能很棘手,因为不同的方法处理编码和转换的方式不同,并且在一个平台(OS X 或 Linux)上看起来工作正常的东西在另一个平台上工作不佳。
问题与您的输出连接以及 Windows 如何处理编码和文本连接有关。我尝试使用 UTF-8 和 8 位编码中的一些希伯来语文本来复制该问题。我们还将介绍文件读取问题,因为那里也可能存在一些问题。
用于测试
创建了一个简短的希伯来语文本文件,编码为 UTF-8:hebrew-utf8.txt
创建了一个简短的希伯来语文本文件,编码为 ISO-8859-8:hebrew-iso-8859-8.txt。 (注意:您可能需要告诉浏览器有关编码的信息才能正确查看此编码 - 例如 Safari 就是这种情况。)
读取文件的方法
现在让我们来试验一下。我正在使用 Windows 7 进行这些测试(它实际上适用于 OS X,我通常使用 OS)。
lines <- readLines("http://kenbenoit.net/files/hebrew-utf8.txt")
lines
## [1] "העברי ×”×•× ×—×‘×¨ בקבוצה ×”×›× ×¢× ×™×ª של שפות שמיות."
## [2] "זו היתה ×©×¤×ª× ×©×œ ×”×™×”×•×“×™× ×ž×•×§×“×, ×בל מן 586 ×œ×¤× ×”\"ס ×–×” התחיל להיות מוחלף על ידי ב×רמית."
失败,因为它假定编码是您的系统编码,Windows-1252。但是因为当你读取文件时没有发生转换,你可以通过将编码位设置为 UTF-8 来解决这个问题:
# this sets the bit for UTF-8
Encoding(lines) <- "UTF-8"
lines
## [1] "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
## [2] "זו היתה שפתם של היהודים מוקדם, אבל מן 586 לפנה\"ס זה התחיל להיות מוחלף על ידי בארמית."
但最好在阅读文件时执行此操作:
# this does it in one pass
lines2 <- readLines("http://kenbenoit.net/files/hebrew-utf8.txt", encoding = "UTF-8")
lines2[1]
## [1] "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
Encoding(lines2)
## [1] "UTF-8" "UTF-8"
现在看看如果我们尝试读取相同的文本但编码为 8 位 ISO 希伯来语代码页会发生什么。
lines3 <- readLines("http://kenbenoit.net/files/hebrew-iso-8859-8.txt")
lines3[1]
## [1] "äòáøé äåà çáø á÷áåöä äëðòðéú ùì ùôåú ùîéåú."
设置编码位在这里没有帮助,因为读取的内容没有映射到希伯来语的 Unicode 代码点,并且 Encoding()
没有实际编码转换,它只是设置了一个额外的位可以用于告诉 R 几个可能的编码值之一。我们可以通过将 encoding = "ISO-8859-8"
添加到 readLines()
调用来解决这个问题。我们还可以在加载后转换文本,使用 iconv()
:
# this will not fix things
Encoding(lines3) <- "UTF-8"
lines3[1]
## [1] "\xe4\xf2\xe1\xf8\xe9 \xe4\xe5\xe0 \xe7\xe1\xf8 \xe1\xf7\xe1\xe5\xf6\xe4 \xe4\xeb\xf0\xf2\xf0\xe9\xfa \xf9\xec \xf9\xf4\xe5\xfa \xf9\xee\xe9\xe5\xfa."
# but this will
iconv(lines3, "ISO-8859-8", "UTF-8")[1]
## [1] "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
总的来说,我认为上面用于 lines2
的方法是最好的方法。
如何输出文件,保留编码
现在回答关于如何编写的问题:最安全的方法是在低级别控制您的连接,您可以在其中指定编码。否则,默认为 R/Windows 选择您的系统编码,这将丢失 UTF-8。我认为这行得通,在 OS X 上绝对没问题 - 在 OS X 上也能正常调用 writeLines()
只是命名文本没有 textConnection 的文件。
## to write lines, use the encoding option of a connection object
f <- file("hebrew-output-UTF-8.txt", open = "wt", encoding = "UTF-8")
writeLines(lines2, f)
close(f)
但它不适用于 Windows。您可以在此处查看 Windows 7 个结果:hebrew-output-UTF-8-file_encoding.txt.
所以,这是如何做到的 在 Windows 中:一旦您确定您的文本编码为 UTF-8,只需将其写为原始字节,不使用任何编码,像这样:
writeLines(lines2, "hebrew-output-UTF-8-useBytesTRUE.txt", useBytes = TRUE)
您可以在 hebrew-output-UTF-8-useBytesTRUE.txt 看到结果,现在是 UTF-8,看起来是正确的。
Added for write.csv
请注意,您想要执行此操作的唯一原因是使 .csv 文件可用于导入其他软件,例如 Excel。 (祝你在 Excel/Windows 中使用 UTF-8 好运...)否则,你应该使用 write(myDataFrame, file = "myDataFrame.RData")
将 data.table 编写为二进制文件。但是如果你真的需要输出.csv,那么:
如何从 Windows
中的data.table
写入 UTF-8 .csv 文件
使用 write.table()
和 write.csv()
编写 UTF-8 文件的问题在于这些打开的文本连接,而 Windows 对 UTF- 8. (This post offers a helpful explanation.) Following from an SO answer posted here,我们可以覆盖它来编写我们自己的函数来输出 UTF-8 .csv 文件。
这假设您已经将任何字符元素的 Encoding()
设置为 "UTF-8"
(这发生在上面为 lines2
导入时)。
df <- data.frame(int = 1:2, text = lines2, stringsAsFactors = FALSE)
write_utf8_csv <- function(df, file) {
firstline <- paste('"', names(df), '"', sep = "", collapse = " , ")
data <- apply(df, 1, function(x) {paste('"', x, '"', sep = "", collapse = " , ")})
writeLines(c(firstline, data), file , useBytes = TRUE)
}
write_utf8_csv(df, "df_csv.txt")
当我们现在在非 Unicode 挑战 OS 中查看该文件时,它现在看起来很好:
KBsMBP15-2:Desktop kbenoit$ cat df_csv.txt
"int" , "text"
"1" , "העברי הוא חבר בקבוצה הכנענית של שפות שמיות."
"2" , "זו היתה שפתם של היהודים מוקדם, אבל מן 586 לפנה"ס זה התחיל להיות מוחלף על ידי בארמית."
KBsMBP15-2:Desktop kbenoit$ file df_csv.txt
df_csv.txt: UTF-8 Unicode text, with CRLF line terminators