数据匠

| ~ read. | Views: 365

谈谈R中的乱码(三)

R

前面讲过,R 中字符向量可以有多种编码。一般情况下,对于混合编码,R 都能很好的自动处理。例如:

x1 <- '中国'
x2 <- iconv(x1, 'GB2312', 'UTF-8')
## == 判断也没问题
x2 == '中国'
## [1] TRUE

x <- c(x1, x2)
grep('中', x)
## [1] 1 2
grep(iconv('中', 'GB2312', 'UTF-8'), x)
## [1] 1 2

在写命令时,无需特意为了目标字符将匹配条件转为相应的编码,R 自动就在后台做了转换。然而,总有些让人意想不到的的角落,例如:

a1 <- iconv('中文 aa', 'gb2312', 'UTF-8')
Encoding(a1)
## [1] "UTF-8"

# 当待替换字符非 UTF-8 编码,替换字符为 UTF-8 编码,结果乱码
(r1 <- sub('aa', a1, 'aa ba'))
## [1] "涓枃 aa ba"
Encoding(r1)
## [1] "unknown"
# 需要手工纠正
Encoding(r1) <- 'UTF-8'
r1
## [1] "中文 aa ba"

(r2 <- sub('aa', a1, 'aa ba', useBytes = F, fixed = T))
## [1] "涓枃 aa ba"
Encoding(r2)
## [1] "unknown"
Encoding(r2) <- 'UTF-8'
r2
## [1] "中文 aa ba"

在线帮助里是这么写的:

For sub and gsub...,..., If useBytes = FALSE a non-ASCII substituted result will often be in UTF-8 with a marked encoding (e.g., if there is a UTF-8 input, and in a multibyte locale unless fixed = TRUE). Such strings can be re-encoded by enc2native.

嗯,这是少数几处帮助文本与实际情况脱离的个例。

待替换字符为 UTF-8 编码,倒是没有问题:

sub('aa', 'bb', a1, fixed = F)
## [1] "中文 bb"

如果是我们自己写的代码,可以小心谨慎,避免跳坑,很容易就能找到替代方案。博主随便列举一下,就有两种:

方式一:坚持极简主义不用第三方包,使用正则表达式之动力引擎 regexpr() 进行替换

s <- 'aa ba'
m <- regexpr('aa', s)
regmatches(s, m) <- a1
s
## [1] "中文 aa ba"

方式二:用包也不羞耻之 stringr

library(stringr)
str_replace('aa', 'aa', a1)
## [1] "中文 aa"
str_replace(a1, 'aa', '+')
## [1] "中文 +"

但是 sub()gsub() 作为R的基础函数,在大量的包中广泛存在,怎么避免让这些包跳坑呢?

本来还想介绍一个与混合编码有关的奇葩案例(来自性能无敌的 data.table 包),但是实在太奇葩了,所以今天就提前收尾吧。

替第四篇做个预告。用过 tm 包的童鞋想必经常碰到为什么 tm 包里词都连起来了? 这样的问题。问题就出在 scan() 这个基础函数(怎么又是基础函数!)。scan()R中用来拆分文本的函数,读取文本数据(read.table())都要用。我记得以前是正常的,但不记得是哪个R版本升级之后,就变成下面这样了,“的”和“分词”被当作了同一个词。scan()的这个奇葩结果就是中文文本分了词让 tm 建矩阵结果还是分的乱七八糟的原因。

x = '测试 中文 的 分词'
scan(text = x, what='', sep=' ')
## [1] "测试"    "中文"    "的 分词"

第四篇将介绍如何修理它。