字符串中的Unescape unicode

时间:2014-07-25 09:16:29

标签: regex json r unicode utf-8

RJSONIO中有一个长期bug用于解析包含unicode转义序列的json字符串。看起来这个bug需要在libjson中修复,这可能不会很快发生,所以我正在寻找在R中创建一个解决方法,在将它们提供给json解析器之前,它们会先发现\uxxxx个序列。 / p>

某些上下文:json数据始终是unicode,默认使用utf-8,因此通常不需要转义。但由于历史原因,json确实支持转义的unicode。因此json数据

{"x" : "Zürich"}

{"x" : "Z\u00FCrich"}

是等效的,并且在解析时应该产生完全相同的输出。但无论出于何种原因,后者在RJSONIO中都不起作用。额外的confusion是由R本身也支持转义的unicode引起的。因此,当我们在R控制台中键入"Z\u00FCrich"时,它会自动正确转换为"Zürich"。要获取实际的json字符串,我们需要转义反斜杠本身,它是json中unicode转义序列的第一个字符:

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

所以我的问题是:在R中给出一个大的json字符串,我怎样才能解除所有转义的unicode序列?即如何用相应的unicode字符替换所有出现的\uxxxx?同样,这里的\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"

3 个答案:

答案 0 :(得分:5)

在玩了这个之后我认为我能做的最好的事情是使用正则表达式搜索\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
}

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

答案 1 :(得分:2)

stringi包中有一个函数:)

require(stringi)    
escaped <- "Z\\u00FCrich"
escaped
## [1] "Z\\u00FCrich"
stri_unescape_unicode(escaped)
## [1] "Zürich"

答案 2 :(得分:1)

也许是这样的?

\"x\"\s:\s\"([^"]*?)\"

这不是看信。等待报价