自动转义unicode字符

时间:2014-08-14 13:12:52

标签: r

如何显示unicode字符串,例如:

x <- "•"

使用其转义的等效文件?

y <- "\u2022"

identical(x, y)
# [1] TRUE

(我希望能够这样做,因为CRAN包必须只包含ASCII,但有时你想在错误信息或类似信息中使用unicode)

4 个答案:

答案 0 :(得分:14)

在深入研究有关iconv的一些文档后,我认为您只能使用base包完成此操作。但是你需要特别注意字符串的编码。

在使用UTF-8编码的系统上:

> stri_escape_unicode("你好世界")
[1] "\\u4f60\\u597d\\u4e16\\u754c"

# use big endian
> iconv(x, "UTF-8", "UTF-16BE", toRaw=T)
[[1]]
[1] 4f 60 59 7d 4e 16 75 4c

> x <- "•"
> iconv(x, "UTF-8", "UTF-16BE", toRaw=T)    
[[1]]
[1] 20 22

但是,如果您使用的是latin1编码系统,则可能会出错。

> x <- "•"
> y <- "\u2022"
> identical(x, y)
[1] FALSE
> stri_escape_unicode(x)
[1] "\\u0095" # <- oops!

# culprit
> Encoding(x)
[1] "latin1"

# and it causes problem for iconv
> iconv(x, Encoding(x), "Unicode")
Error in iconv(x, Encoding(x), "Unicode") : 
  unsupported conversion from 'latin1' to 'Unicode' in codepage 1252
> iconv(x, Encoding(x), "UTF-16BE")
Error in iconv(x, Encoding(x), "UTF-16BE") : 
  embedded nul in string: '\0•'

在转换为Unicode之前将字符串转换为UTF-8更安全:

> iconv(enc2utf8(enc2native(x)), "UTF-8", "UTF-16BE", toRaw=T)
[[1]]
[1] 20 22

编辑:对于某些特定系统上已经采用UTF-8编码的字符串,这可能会导致一些问题。也许在转换前检查编码会更安全。

> Encoding("•")
[1] "latin1"
> enc2native("•")
[1] "•"
> enc2native("\u2022")
[1] "•"
# on a Windows with default latin1 encoding
> Encoding("测试") 
[1] "UTF-8"
> enc2native("测试") 
[1] "<U+6D4B><U+8BD5>"   # <- BAD! 

对于某些角色或语言,UTF-16可能还不够。所以你可能应该使用UTF-32,因为

  

字符的UTF-32形式是其代码点的直接表示。

基于上述试验和错误,下面可能是我们可以编写的一个更安全的逃避函数:

unicode_escape <- function(x, endian="big") {
  if (Encoding(x) != 'UTF-8') {
    x <- enc2utf8(enc2native(x))
  }
  to.enc <- ifelse(endian == 'big', 'UTF-32BE', 'UTF-32LE')

  bytes <- strtoi(unlist(iconv(x, "UTF-8", "UTF-32BE", toRaw=T)), base=16)
  # there may be some better way to do thibs.
  runes <- matrix(bytes, nrow=4)
  escaped <- apply(runes, 2, function(rb) {
    nonzero.bytes <- rb[rb > 0]
    ifelse(length(nonzero.bytes) > 1, 
           # convert back to hex
           paste("\\u", paste(as.hexmode(nonzero.bytes), collapse=""), sep=""),
           rawToChar(as.raw(nonzero.bytes))
           )
  })
  paste(escaped, collapse="")
}

试验:

> unicode_escape("•••ERROR!!!•••")
[1] "\\u2022\\u2022\\u2022ERROR!!!\\u2022\\u2022\\u2022"
> unicode_escape("Hello word! 你好世界!")
[1] "Hello word! \\u4f60\\u597d\\u4e16\\u754c!"
> "\u4f60\u597d\u4e16\u754c"
[1] "你好世界"

答案 1 :(得分:7)

stringi有一个执行此操作的方法

stri_escape_unicode(y)
# [1] "\\u2022"

答案 2 :(得分:1)

我写了一个名为uniscape的小程序包,该程序包可以将非ASCII字符转换为相应的"\u1234""\U12345678" Unicode转义码(显然带有文字反斜杠)。它可以对任何字符或仅对R字符串(单引号或双引号)中的字符执行此操作。以下示例显示u_escape如何转换字符。然后,输出用引号引起来,进行解析和评估。最终结果与原始字符匹配。

x <- rawToChar(as.raw(c(0xe2, 0x80, 0xa2)))
Encoding(x) <- "UTF-8"
x
# [1] "•"
x_u <- uniscape::u_escape(x)
x_u
# [1] "\\u2022"
y <- eval(parse(text = paste0('"', x_u, '"')))
y
# [1] "•"
identical(x, y)
# [1] TRUE

该软件包(位于GitHub上)还提供了RStudio插件以方便使用。插件在活动的源代码编辑器文档上运行。除rstudioapi外,该程序包没有其他任何硬性依赖。

此图显示了具有选定文本区域的示例文档以及具有三个uniscape插件的RStudio插件窗口。已选择“转义选择”加载项。 Example document and addin window

这是应用“转义选择”后的结果,每个非ASCII字符的编码顺序会自动突出显示(选中)。 Result of Escape selection addin

撤消上一个操作后,这是“文件中转义字符串”的结果。插件会自动突出显示活动文件中每个受影响的 R字符串。带注释的字符串将被忽略。 “转义所选字符串”功能相同,但仅适用于所选文本区域。 Result of Escape strings in file

答案 3 :(得分:0)

R在C语言环境中自动转义unicode:

x <- "•"
Sys.setlocale(locale = 'C')
print(x)
# [1] "<U+2022>"