如何正确处理R中的转义Unicode字符,例如em破折号( - )

时间:2012-02-10 06:43:25

标签: r unicode

我在处理R中的转义unicode字符时遇到问题,特别是在从MediaWiki API获取信息时遇到的问题。我会找到像

这样的JSON字符串
{"query":{"categorymembers":[{"ns":0,"title":"Banach\u2013Tarski paradox"}]}}

哪个应该是完全有效的,但通过fromJSON()读入时,我得到:

snip...
[1] "Banach\023Tarski paradox"

最初我认为这只是RJSONIO的一个问题,但我遇到scan()readLines()的类似问题。我的猜测是我遗漏了一些非常基本的东西。

我实际上无法使用 R给出完全可重现的示例,因为如果我通过write()(或某些等效函数)将“em \ u2013dash”发送到文件,R将自动转换为他们冲刺。所以这里。使用以下命令创建名为test1的文本文件:

"em\u2013dash" "em–dash" " em \u2013 dash"

然后加载R(无论文件路径是什么):

> scan( file = "~/R/test1", what = "character", encoding = "UTF-8")
Read 3 items
[1] "em\\u2013dash"    "em–dash"          " em \\u2013 dash"
> readLines("~/R/test1", warn = FALSE, encoding = "UTF-8")
[1] "\"em\\u2013dash\" \"em–dash\" \" em \\u2013 dash\""

添加的转义字符是导致fromJSON()出现问题的原因。我可以把它们剥离出来,但我可能会在这个过程中打破其他东西,我想有一个更简单的解决方案。谢谢。

以下是会话信息:

R version 2.14.1 (2011-12-22)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

locale:
[1] C/en_US.UTF-8/C/C/C/C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] RJSONIO_0.98-0

loaded via a namespace (and not attached):
[1] tools_2.14.1

3 个答案:

答案 0 :(得分:9)

这实际上不是RJSONIO中的错误。它的设计目的是期望一个由R读取并且已经处理过非ASCII字符的字符串。当一个字符串传递一个带有\ u的字符串时,该字符串尚未处理但已转义。 在我的机器上,语言环境设置为en_US.UTF-8,命令

fromJSON('{"query":{"categorymembers":[{"ns":0,"title":"Banach\u2013Tarski paradox"}]}}')

产生

$query
$query$categorymembers
$query$categorymembers[[1]]
$query$categorymembers[[1]]$ns
[1] 0

$query$categorymembers[[1]]$title
[1] "Banach–Tarski paradox"

请注意,该字符的前缀为\u而不是\\u。 只需输入该字符串,即可查看它在R中的显示方式。

所以问题是fromJSON()的上游,为什么字符串包含\ u。
我可以在RJSONIO中添加对处理此类未处理字符串的支持。

答案 1 :(得分:5)

这是RJSONIO中的错误,因为您可以清楚地看到:

> RJSONIO::fromJSON('{"x":"foo\\u2013bar"}')
           x 
"foo\023bar" 

rjson

中工作得很好
> rjson::fromJSON('{"x":"foo\\u2013bar"}')
$x
[1] "foo–bar"

并证明它是正确的值:

 > Sys.setlocale("LC_ALL", "C")
[1] "C/C/C/C/C/en_US.UTF-8"
> rjson::fromJSON('{"x":"foo\\u2013bar"}')
$x
[1] "foo<U+2013>bar"

在您的分析中,您对打印字符串与实际字符串感到困惑。 print引用其内容进行打印 - 如果要查看实际字符串,可以使用catcharToRaw。此外scan不解释任何逃脱,所以你得到你给它的东西。

答案 2 :(得分:1)

我认为根本问题是libjson中未启用RJSONIO选项JSON_UNICODE。但是,当输入为UTF-8编码时,似乎问题并未表现出来:

library(RJSONIO)
x = "北京填鴨们"
identical(x, fromJSON(toJSON(x)))
# [1] TRUE

仅当输入使用JSON转义字符时才会出现此问题。在这些情况下,RJSONIO似乎会生成latin1输出,但不会标记正确设置编码:

x <- fromJSON('["Z\\u00FCrich"]')
print(x)
# [1] "Z\xfcrich"

nchar(x)
#Error in nchar(x) : invalid multibyte string 1

对于这个简单的示例,我们可以通过手动将编码设置为latin1来修复它:

#Set the correct encoding
Encoding(x) <- "latin1"
print(x)
#[1] "Zürich" 

但是,这当然不适用于latin1集之外的字符:

#This should be: "填"
fromJSON('["\\u586B"]')