在Windows和Unix下使用unicode替换的R中的gsub函数会产生不同的结果吗?

5
在Mac或Linux下在R中运行以下命令会产生预期结果,即希腊字母beta:
gsub("<U\\+[0-9A-F]{4}>", "\u03B2", "<U+03B2>")

"\u03B2"

然而,在Windows下运行第一个命令会产生错误结果,但第二个命令会给出正确的beta输出。我在Windows上尝试了3个版本的R(3.0.2、3.1.1和3.1.2)。它们都一致地打印出“错误”的结果。(由于我现在无法访问Windows,所以无法发布输出。)
此外,是否可以使用gsub将格式为<U+FFFF>(忽略空格,因为没有它网站不显示任何内容)的Unicode转换为"\uFFFF"?
非常感谢。
更新:
借鉴MrFlick的解决方案,我对以下丑陋的解决方案进行了修改,以防止句子中有多个Unicode。然而,修复方法真的很丑陋,所以请随意发布改进意见。
test.string <- "This is a <U+03B1> <U+03B2> <U+03B2> <U+03B3> test <U+03B4> string."

trueunicode.hack <- function(string){
    m <- gregexpr("<U\\+[0-9A-F]{4}>", string)
    if(-1==m[[1]][1])
        return(string)

    codes <- unlist(regmatches(string, m))
    replacements <- codes
    N <- length(codes)
    for(i in 1:N){
        replacements[i] <- intToUtf8(strtoi(paste0("0x", substring(codes[i], 4, 7))))
    }

    # if the string doesn't start with a unicode, the copy its initial part
    # until first occurrence of unicode
    if(1!=m[[1]][1]){
        y <- substring(string, 1, m[[1]][1]-1)
        y <- paste0(y, replacements[1])
    }else{
        y <- replacements[1]
    }

    # if more than 1 unicodes in the string
    if(1<N){
        for(i in 2:N){
            s <- gsub("<U\\+[0-9A-F]{4}>", replacements[i], 
                      substring(string, m[[1]][i-1]+8, m[[1]][i]+7))
            Encoding(s) <- "UTF-8"
            y <- paste0(y, s)
        }
    }

    # get the trailing contents, if any
    if( nchar(string)>(m[[1]][N]+8) )
        y <- paste0( y, substring(string, m[[1]][N]+8, nchar(string)) )
    y
}

test.string
trueunicode.hack(test.string)

结果:

"This is a <U+03B1> <U+03B2> <U+03B2> <U+03B3> test <U+03B4> string."
"This is a α β β γ test δ string."

问题可能是由于默认情况下,Linux和Mac R使用UTF-8作为默认编码,而Windows使用Latin1。由于您无法准确描述错误,这使得帮助变得困难(我也不在Windows机器上)。我建议检查涉及的字符向量的“Encoding()”。 - MrFlick
它看起来像是一个带帽的小写字母"a",后面跟着三个大于号">>>"。 - CloudyTrees
@MrFlick 这是错误的。Windows 仅使用 UTF16(早期版本中为 UCS2)。代码页仅适用于非 Unicode 应用程序,即那些使用 char * 并调用 ANSI API 方法而不是 wchar *char16_t *(作弊,这是 C++11 类型)。在此问题上,R 是不一致的,有些软件包使用宽字符串,有些使用窄字符串,具体取决于系统的locale 是否为 UTF8。有些可以处理 Unicode 文本而不会出现问题,而其他则会损坏它。 - Panagiotis Kanavos
2个回答

13

如果您在Windows上没有看到正确的字符,请尝试明确设置编码。

x <- gsub("<U\\+[0-9A-F]{4}>", "\u03B2", "<U+03B2>")
Encoding(x) <- "UTF-8"
x

关于用unicode字符替换所有这些符号,我已经改编了这个答案来做类似的事情。这里我们将unicode字符作为原始向量生成。这是一个辅助函数。

trueunicode <- function(x) {
    packuni<-Vectorize(function(cp) {
        bv <- intToBits(cp)
        maxbit <- tail(which(bv!=as.raw(0)),1)
        if(maxbit < 8) {
            rawToChar(as.raw(codepoint))
        } else if (maxbit < 12) {
            rawToChar(rev(packBits(c(bv[1:6], as.raw(c(0,1)), bv[7:11], as.raw(c(0,1,1))), "raw")))
        } else if (maxbit < 17){
            rawToChar(rev(packBits(c(bv[1:6], as.raw(c(0,1)), bv[7:12], as.raw(c(0,1)), bv[13:16], as.raw(c(0,1,1,1))), "raw")))    
        } else {
           stop("too many bits")
        }
    })
    m <- gregexpr("<U\\+[0-9a-fA-F]{4}>", x)
    codes <- regmatches(x,m)
    chars <- lapply(codes, function(x) {
        codepoints <- strtoi(paste0("0x", substring(x,4,7)))
        packuni(codepoints)

    })
    regmatches(x,m) <- chars
    Encoding(x)<-"UTF-8"
    x
}

然后我们可以像这样使用它

x <- c("beta <U+03B2>", "flipped e <U+018F>!", "<U+2660> <U+2663> <U+2665> <U+2666>")
trueunicode(x)
# [1] "beta β"       "flipped e Ə!" "♠ ♣ ♥ ♦"

非常感谢。有没有想法如何修复一个句子中出现多个 Unicode 的情况?我有一种基于你的解决方案的 hack,但不是很好。 - CloudyTrees
1
只是一个快速的提示,当字符串中没有Unicode时,这种情况不被考虑在内。感谢您提供的解决方案。 - CloudyTrees

2

为了进一步解释@MrFlick的解决方案,您必须在每次使用gsub处理字符串后设置编码,如下:

s <- "blah<U+03B2>blah-blah<U+03B2>blah-blah<U+03B2>blah"
# setting the encoding here and not in the while loop will not fix the problem
{
while(grepl('<U\\+[0-9A-Fa-f]{4}>',s)){
    newVal <- gsub('^.*<U\\+([0-9A-Fa-f]{4})>.*$','"\\\\u\\1"',s)
    newVal <- eval(parse(text=newVal))
    cat(newVal,'\n')
    s <- gsub('^(.*)<U\\+[0-9A-Fa-f]{4}>(.*)$',
              paste0('\\1',newVal,'\\2'),
              s)
    # setting the encoding here fixes the cross platform differences
    Encoding(s) <- 'UTF-8'
}
cat(s,'\n')
# setting the encoding here and not in the while loop will raise an error
}
Encoding(s)

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