前面讲过,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
andgsub
...,..., IfuseBytes = 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 unlessfixed = TRUE
). Such strings can be re-encoded byenc2native
.
嗯,这是少数几处帮助文本与实际情况脱离的个例。
待替换字符为 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] "测试" "中文" "的 分词"
第四篇将介绍如何修理它。