解决 OS 与 list.files() 对重音字符的处理

resolving OS vs list.files() handling of accented characters

我正在纠正一些学生的作业,他们的名字中有重音字符(不是我的本地语言环境),并且愚蠢地决定在创建带有我的评论的文件时尊重他们名字的实际拼写(Firstname.Lastname ).通常,我创建了文件名(在控制台中或在 Emacs 中使用 Compose 键(例如 compose-'-a 生成 á)。这导致 OS 和 R 的 list.files():

system("touch testá")      ## create file with accented character in name
list.files(pattern="test") ## it's there ...
## [1] "testá"

但是当我尝试匹配 pattern 参数中的整个单词时...

list.files(pattern="testá")
## character(0)

这是在 Xubuntu 16.04 上,但它是一个虚拟机,所以底层文件系统是 HFS。我的正常语言环境是

[1] "LC_CTYPE=en_CA.UTF8;LC_NUMERIC=C;LC_TIME=en_CA.UTF8;LC_COLLATE=en_CA.UTF8;LC_MONETARY=en_CA.UTF8;LC_MESSAGES=en_CA.UTF8;LC_PAPER=en_CA.UTF8;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=en_CA.UTF8;LC_IDENTIFICATION=C"

但通过 Sys.setlocale("LC_ALL","pl_PL.UTF8") 切换它(显然成功)没有帮助。

(对我而言)真正奇怪的是,用 "testł" 做同样的练习 有效 ...

根据评论中的建议,我对 charToRaw 进行了更多探索。实际上,R 中的字符串表示与存储在磁盘上的名称之间存在差异:

charToRaw("testá")
## [1] 74 65 73 74 c3 a1
charToRaw(list.files(pattern="test"))
## [1] 74 65 73 74 61 cc 81

我在 Mac 和你一样。尝试给出 "test\u00e1" 的模式,这就是我的 as.hexmode(utf8ToInt("á")) 所说的 ASCII 值:

最终建议用蛮力解决手头的问题。

> file.rename("testá", "testXXX")
[1] TRUE
> list.files(pattern="testXXX")
[1] "testXXX"

和 R Yoda 一样,我首先查看了 charToRaw 并收到了错误的翻译,我得到了这个:

> "\u00e1"
[1] "á"
> "test\uc3a1"
[1] "test쎡"

感谢@42- 和@RYoda 提供的线索:因为我的底层文件系统是 HFS+,所以我能够找到这个 blog post on "HFS+ and utf8 accented characters", which led me to this SO question & answer on Unicode normalization,从而找到解决方案

list.files(pattern=stringi::stri_trans_nfd("testá"))

其中 ?stri_trans_nfd 让我们知道 "nfd" 代表

• NFD (Canonical Decomposition),