字符串中的Unicode解码

10

RJSONIO中存在一个长期以来的错误,用于解析包含Unicode转义序列的JSON字符串。似乎需要在libjson中修复此错误,但这可能不会很快发生,因此我正在寻找在R中创建解除转义\uxxxx序列的解决方法,然后再将其提供给json解析器。

一些背景:JSON数据始终是Unicode格式,默认情况下使用utf-8,因此通常不需要进行转义。但由于历史原因,JSON确实支持转义的Unicode。因此,JSON数据

{"x" : "Zürich"}

{"x" : "Z\u00FCrich"}

这两种写法等价,解析时应该得到完全相同的输出。但由于某些原因,RJSONIO 中后一种写法无效。此外,R 本身也支持转义 Unicode。因此,当我们在 R 控制台输入 "Z\u00FCrich" 时,它会自动正确转换为 "Zürich",导致进一步的 混淆。要获取实际的 JSON 字符串,我们需要转义 json 中 unicode 转义序列的第一个字符——反斜杠本身:

test <- '{"x" : "Z\\u00FCrich"}'
cat(test)

我的问题是:在R语言中,如何处理一个大的json字符串,将所有转义的unicode序列还原?即如何将所有\uxxxx的出现替换为相应的unicode字符?这里的\uxxxx表示一个由6个字符组成的实际字符串,以反斜杠开头。因此,一个unescape函数应该满足以下条件:

#Escaped string
escaped <- "Z\\u00FCrich"

#Unescape unicode
unescape(escaped) == "Zürich"

#This is the same thing
unescape(escaped) == "Z\u00FCrich"

有一件事可能会使事情变得复杂,那就是如果反斜杠本身在json中用另一个反斜杠转义,则它不是Unicode转义序列的一部分。例如,unescape 也应该满足:

#Watch out for escaped backslashes
unescape("Z\\\\u00FCrich") == "Z\\\\u00FCrich"
unescape("Z\\\\\\u00FCrich") == "Z\\\\ürich"

我在这里遇到了类似的问题:http://stackoverflow.com/questions/20067206/reading-unescaped-backslashes-in-json-into-r 不确定是否有任何简单的解决方案。 - Hong Ooi
那是一个不同的问题。你正在尝试解析无效的JSON。 - Jeroen Ooms
3个回答

9

在进一步尝试后,我认为最好的方法是使用正则表达式搜索\uxxxx模式,然后使用R解析器对其进行解析:

unescape_unicode <- function(x){
  #single string only
  stopifnot(is.character(x) && length(x) == 1)

  #find matches
  m <- gregexpr("(\\\\)+u[0-9a-z]{4}", x, ignore.case = TRUE)

  if(m[[1]][1] > -1){
    #parse matches
    p <- vapply(regmatches(x, m)[[1]], function(txt){
      gsub("\\", "\\\\", parse(text=paste0('"', txt, '"'))[[1]], fixed = TRUE, useBytes = TRUE)
    }, character(1), USE.NAMES = FALSE)

    #substitute parsed into original
    regmatches(x, m) <- list(p)
  }

  x
}

这似乎适用于所有情况,我还没有发现任何奇怪的副作用


2
这个功能在 stringi 包中有实现 :)
require(stringi)    
escaped <- "Z\\u00FCrich"
escaped
## [1] "Z\\u00FCrich"
stri_unescape_unicode(escaped)
## [1] "Zürich"

这些测试失败了,因为它也会将换行符、制表符、反斜杠等字符进行转义。然而 json 需要这些字符继续被转义。我仅仅想要取消转义 \u 序列,不需要其他的操作。 - Jeroen Ooms

1
也许像这样吗?
\"x\"\s:\s\"([^"]*?)\"

这不是寻找信件。只是等待报价。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接