为什么 stringr 在操作字符串时改变编码?

Why is stringr changing encoding when manipulating strings?

stringr有这种奇怪的行为,真让我恼火。 stringr 在没有警告的情况下改变了一些包含奇异字符的字符串的编码,在我的例子中是 ø、å、æ、é 和其他一些......如果你 str_trim 一个字符向量,那么那些带有外来字母将转换为新的编码。

letter1 <- readline('Gimme an ASCII character!')     # try q or a
letter2 <- readline('Gimme an non-ASCII character!') # try ø or é
Letters <- c(letter1, letter2)
Encoding(Letters)           # 'unknown'
Encoding(str_trim(Letters)) # mixed 'unknown' and 'UTF-8'

这是一个问题,因为我使用 data.table 来(快速)合并大表,而 data.table 不支持混合编码,而且我找不到返回到统一编码。

有什么变通办法吗?

编辑:我想我可以回到基本功能,但它们也不保护编码。 paste 保留它,但不 sub 例如。

 Encoding(paste(' ', Letters))                 # 'unknown'
 Encoding(str_c(' ', Letters))                 # mixed
 Encoding(sub('^ +', '', paste(' ', Letters))) # mixed

stringr 正在更改编码,因为 stringrstringi 包的包装器,并且 stringi 始终以 UTF-8 编码。有关此设计选择的详细信息和解释,请参阅 help("stringi-encoding", package = "stringi")

为避免合并 data.table 时出现问题,只需确保所有 id 变量均以 UTF-8 编码。您可以使用 stringi 包中的 stri_enc_toutf8 或使用 iconv.

R 并不总是使编码之间的转换变得容易(有函数 iconv,但此函数接受的内容取决于平台)。但是,至少您始终可以将字符串的编码标记重置为“未知”:

Letters = str_trim(Letters)
Encoding(Letters)
# [1] "unknown" "UTF-8"
Encoding(Letters) = ''
Encoding(Letters)
# [1] "unknown" "unknown"

但是,请注意,这只是 标记 字符串的编码,实际上并没有重新编码字符串。因此,这会导致数据出现乱码。正如评论中所提到的,这充其量只是一个 hack,而不是问题的实际解决方案。

Encoding 举例说明了 R 无法正确处理编码的问题。文档说:

ASCII strings will never be marked with a declared encoding, since their representation is the same in all supported encodings.

… 这显然根本没有帮助(而且还有点误导;仅由 < 128 的代码点组成的 UTF-8 字符串可能看起来与 ASCII 字符串没有区别,但对其进行操作应该会产生不同的结果,具体取决于关于编码,这就是为什么它应该有效标记的原因)。

有趣的是,enc2nativeenc2utf8 都不会在这里完成所需的事情 — 两者都会对 Letters 中的两个字符串产生不同的编码,这是 Encoding 上面引用的问题。

有了 this recent commit,data.table 现在通过确保在创建 data.table 时使用正确的编码以及通过确保 [=] 等函数中的正确编码来隐式处理这些混合编码10=] 和 duplicated().

查看 README.md 中 v1.9.7 的错误下的新闻项目 (23)。

如果您遇到任何进一步的问题,请测试并回信。