一尘不染

字符串中的转义unicode

json

在解析包含unicode转义序列的json字符串时,存在一个长期存在的错误RJSONIO。似乎需要修复该错误,这种错误libjson可能很快就不会发生,因此我正在寻找一种在R中创建解决方法的方法,该方法在将\uxxxx序列提供给json解析器之前先取消序列化。

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

{"x" : "Zürich"}

{"x" : "Z\u00FCrich"}

是等效的,并且在解析时应产生完全相同的输出。但是无论出于什么原因,后者都不起作用RJSONIO。R本身也支持转义的unicode,这引起了进一步的混乱。因此,当我们输入"Z\u00FCrich"R控制台时,它会自动正确转换为"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"

阅读 301

收藏
2020-07-27

共1个答案

一尘不染

在玩了更多之后,我认为我能做的最好的就是\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
}

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

2020-07-27