==和%in%根据字符编码而不同?

Roy*_*lTS 15 r character-encoding

我很难理解为什么==并且%in%在应用于依赖于矢量编码时依赖的字符向量时会产生不同的结果.一个例子:

a <- 'Köln'
Encoding(a) <- 'unknown'
Encoding(a)
# [1] "unknown"

b <- a
Encoding(b) <- 'UTF-8'

a == b
# [1] TRUE
a %in% b
# [1] FALSE
Run Code Online (Sandbox Code Playgroud)

更新:

结果似乎也取决于平台.这两个陈述回归:

  • TRUEFALSE对OS X 10.11.5ř3.3.0
  • FALSEFALSEWindows 10上的R 3.3.0(64位)
  • TRUETRUE上在CentOS 7 R 3.2.3

我开始认为这是一个错误.

Pey*_*ton 3

这确实是一个bug,并且在3.3.1中修复了。

\n\n

这种行为实际上比您的示例所示的更奇怪,因为只有FALSE当 的左侧有一个元素时,您才会得到%in%

\n\n
> a %in% b\n[1] FALSE\n> c(a, a) %in% b\n[1] TRUE TRUE\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如评论所暗示的,%in%只需调用match,因此问题也可以在那里看到:

\n\n
> match(a, b)\n[1] NA\n> match(c(a, a), b)\n[1] 1 1\n
Run Code Online (Sandbox Code Playgroud)\n\n

%in%和 的重要参数matchxtable,其中任一函数搜索xin table。在幕后,R 在match5中定义的函数中执行此操作unique.c。如果您有多个xmatch5将创建一个哈希表table以启用快速查找。如果你深入研究代码,你会发现比较是在一个名为 的函数中完成的sequal,该函数返回Seql(STRING_ELT(x, i), STRING_ELT(y, j))(嗯,它实际上比这个复杂一点*)。然后如果你查看Seqlin memory.c,你会发现:

\n\n
int result = !strcmp(translateCharUTF8(a), translateCharUTF8(b));\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如您所看到的,它将字符串转换为 UTF-8。

\n\n

但是,如果x只有一个元素,那么创建哈希表的麻烦就很愚蠢,因为我们只需扫描table一次即可查看是否x存在。在 3.3.0 中,检查x和 每个元素之间是否相等的代码table没有使用Seql,也没有将字符串转换为 UTF-8。但从 3.3.1 开始,Seql使用了,因此行为是固定的。

\n\n

* 关于字符串相等性的一点:R 实际上会缓存字符串,这样它就不必存储一堆副本。因此,如果两个字符串位于同一位置,则它们相等,无需进一步检查!

\n\n
> .Internal(inspect("K\xc3\xb6ln"))\n@10321b758 16 STRSXP g0c1 [NAM(2)] (len=1, tl=0)\n  @106831eb8 09 CHARSXP g1c1 [MARK,gp=0x28,ATT] [UTF8] [cached] "K\xc3\xb6ln"\n> .Internal(inspect(b))\n@106831cd8 16 STRSXP g1c1 [MARK,NAM(2)] (len=1, tl=0)\n  @106831eb8 09 CHARSXP g1c1 [MARK,gp=0x28,ATT] [UTF8] [cached] "K\xc3\xb6ln"\n
Run Code Online (Sandbox Code Playgroud)\n