• R语言
  • 求助:RStudio读取日文文件名乱码

问题描述

最近的数据分析涉及英语和日语文档,时不时出现乱码,正在尝试一个个解决。其中一个是用list.files()读取文件名后,在RStudio的Console板块输出结果为乱码的问题。查阅字符编码相关资料,加上自己尝试更改电脑语言和区域设置后,认为这主要和电脑系统的区域设置有关,详细位置是Settings > Region > Additional date, time & regional > Change date, time, or number format > Administrative > Language for non-Unicode programs settings,下面简称该项设置为“非Unicode程序语言设置”。实验过程和代码详述如下。我的问题是:

  • 能否在不改变电脑非Unicode程序语言设置的情况下正确读取并显示示例日文文件名?
  • 通过改变电脑非Unicode程序语言设置和Sys.setlocale()实现正确读取的方法会不会有什么副作用?比如在后续读取其他语言的数据、数据文件或文件名的时候是否会出问题?

代码和结果

首先在目录C:\Users\kangj\Documents\R\Other\cosx_mojibake\File下放入一个PDF文件,命令为“京都市とさいたま市.pdf”。然后在不同系统语言、区域格式设置和非Unicode程序语言设置下读取该文件的文件名,看看是否正常显示,以及能否正常查找到这个文件。这三个因素中,系统语言就是电脑的界面语言,区域格式设置则和日期时间等的显示格式有关,非Unicode程序语言设置的话,我不太清楚,似乎和一些非UTF-8软件或文件的默认打开方式有关?由于经过简单对比发现,系统语言和区域格式设置这两个因素和本问题没有关系,所以这里只展示在不同非Unicode程序语言设置下的结果,以下代码系统语言均为英语,区域格式设置也均为英语。此外,在非Unicode程序语言设置中,有一个“Use Unicode UTF-8 for worldwide language support”的选框,均不勾选。以下代码中,前面带一个#的是代码注释,带##的是运行结果。

第1种情况 非Unicode程序语言设置为日语:

# 注意先设置好工作路径为“京都市とさいたま市.pdf”所在文件夹
# 第一步:不改变Sys.setlocale()测试
# 查看此时的sessionInfo()
sessionInfo()
##R version 4.0.3 (2020-10-10)
##Platform: x86_64-w64-mingw32/x64 (64-bit)
##Running under: Windows 10 x64 (build 19042)
##
##Matrix products: default
##
##locale:
##[1] LC_COLLATE=Japanese_Japan.932  LC_CTYPE=Japanese_Japan.932   
##[3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C                  
##[5] LC_TIME=Japanese_Japan.932    
##
##attached base packages:
##[1] stats     graphics  grDevices utils     datasets  methods   base     
##
##loaded via a namespace (and not attached):
## [1] compiler_4.0.3  htmltools_0.5.0 tools_4.0.3     yaml_2.2.1      rmarkdown_2.5  
## [6] knitr_1.30      xfun_0.18       digest_0.6.27   rlang_0.4.8     evaluate_0.14  
list.files()
##[1] "京都市とさいたま市.pdf"
# 将结果代入看看能否查找到对应文件
"‹ž“sŽs‚Æ‚³‚¢‚½‚ÜŽs.pdf" %in% list.files()
##[1] FALSE
# 将原文件名代入看能否查找到
"京都市とさいたま市.pdf" %in% list.files()
##[1] TRUE

# 第二步:改变Sys.setlocale()后测试
Sys.setlocale(category = "LC_ALL", locale = "Japanese")
##[1] "LC_COLLATE=Japanese_Japan.932;LC_CTYPE=Japanese_Japan.932;
##LC_MONETARY=Japanese_Japan.932;LC_NUMERIC=C;LC_TIME=Japanese_Japan.932"
sessionInfo()
##R version 4.0.3 (2020-10-10)
##Platform: x86_64-w64-mingw32/x64 (64-bit)
##Running under: Windows 10 x64 (build 19042)
##
##Matrix products: default
##
##locale:
##[1] LC_COLLATE=Japanese_Japan.932  LC_CTYPE=Japanese_Japan.932   
##[3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C                  
##[5] LC_TIME=Japanese_Japan.932    
##
##attached base packages:
##[1] stats     graphics  grDevices utils     datasets  methods   base     
##
##loaded via a namespace (and not attached):
## [1] compiler_4.0.3  htmltools_0.5.0 tools_4.0.3     yaml_2.2.1      rmarkdown_2.5  
## [6] knitr_1.30      xfun_0.18       digest_0.6.27   rlang_0.4.8     evaluate_0.14  
list.files()
##[1] "京都市とさいたま市.pdf"
"京都市とさいたま市.pdf" %in% list.files()
##[1] TRUE
# 那通过第一步生成的乱码还能查找到对应文件吗
"‹ž“sŽs‚Æ‚³‚¢‚½‚ÜŽs.pdf" %in% list.files()
##[1] FALSE

# 这时候如果把Sys.setlocale()又改回英语的话,结果会和第一步相同,不赘述

第2种情况 非Unicode程序语言设置为中文:

# 第一步:不改变Sys.setlocale()测试
# 查看此时的sessionInfo()
sessionInfo()
##R version 4.0.3 (2020-10-10)
##Platform: x86_64-w64-mingw32/x64 (64-bit)
##Running under: Windows 10 x64 (build 19042)
##
##Matrix products: default
##
##locale:
##[1] LC_COLLATE=Japanese_Japan.932  LC_CTYPE=Japanese_Japan.932   
##[3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C                  
##[5] LC_TIME=Japanese_Japan.932    
##system code page: 1252
##
##attached base packages:
##[1] stats     graphics  grDevices utils     datasets  methods   base     
##
##loaded via a namespace (and not attached):
## [1] compiler_4.0.3  htmltools_0.5.0 tools_4.0.3     yaml_2.2.1      rmarkdown_2.5  
## [6] knitr_1.30      xfun_0.18       digest_0.6.27   rlang_0.4.8     evaluate_0.14  
list.files()
##[1] "?????????.pdf"
# 将结果代入看看能否查找到对应文件
"?????????.pdf" %in% list.files()
##[1] TRUE
# 将原文件名代入看能否查找到
"京都市とさいたま市.pdf" %in% list.files()
##[1] FALSE

# 第二步:改变Sys.setlocale()后测试
Sys.setlocale(category = "LC_ALL", locale = "Japanese")
##[1] "LC_COLLATE=Japanese_Japan.932;LC_CTYPE=Japanese_Japan.932;
##LC_MONETARY=Japanese_Japan.932;LC_NUMERIC=C;LC_TIME=Japanese_Japan.932"
sessionInfo()
##R version 4.0.3 (2020-10-10)
##Platform: x86_64-w64-mingw32/x64 (64-bit)
##Running under: Windows 10 x64 (build 19042)
##
##Matrix products: default
##
##locale:
##[1] LC_COLLATE=Japanese_Japan.932  LC_CTYPE=Japanese_Japan.932   
##[3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C                  
##[5] LC_TIME=Japanese_Japan.932    
##system code page: 1252
##
##attached base packages:
##[1] stats     graphics  grDevices utils     datasets  methods   base     
##
##loaded via a namespace (and not attached):
## [1] compiler_4.0.3  htmltools_0.5.0 tools_4.0.3     yaml_2.2.1      rmarkdown_2.5  
## [6] knitr_1.30      xfun_0.18       digest_0.6.27   rlang_0.4.8     evaluate_0.14  
list.files()
##[1] "?????????.pdf"
# 将原文件名代入看能否查找到
"京都市とさいたま市.pdf" %in% list.files()
##[1] FALSE
# 通过和第一步生成的乱码一致的这个文件名查找,还能找到对应文件吗
"?????????.pdf" %in% list.files()
##[1] TRUE

可见只有在满足两个条件,即非Unicode程序语言设置为日语,并且在RStudio中设置Sys.setlocale(category = "LC_ALL", locale = "Japanese")的情况下,才能在Console面板上正确显示示例日语文件名。对于字符编码所知甚少的我而言,这就像是一个电路黑箱,而这两个条件就像是通向小灯泡的串联电路一样……所以有了本文开头提到的两个问题,在此重申并补充一下问题:

  • 通过改变电脑非Unicode程序语言设置和Sys.setlocale()实现正确读取的原因是什么?我的猜测是:RStudio中代码在访问目标文件夹中的日语文件名文件时,采用的时系统的非Unicode程序语言设置,只有该设置为日语时,读入的“某个值”才是日语,然后这个值要输出到RStudio的Console面板时会再经历一次转码,这个过程中如果RStudio的Sys.setlocale()不是日语的话,就会输出乱码。不知道这个猜测距离真相有多远。
  • 能否在不改变电脑非Unicode程序语言设置的情况下正确读取并显示示例日文文件名?比如通过某些指令中的encoding或者fileEncoding选项,或者是通过iconv()函数转码?有这个问题,原因主要是怕系统设置的更改会影响其他软件,比如现在我打开*.csv或者MS Excel文件的时候,字体就怪怪的,可能被当作日语处理了吧。
  • 通过改变电脑非Unicode程序语言设置和Sys.setlocale()实现正确读取的方法会不会有什么副作用?比如在后续读取其他语言的数据、数据文件或文件名的时候是否会出问题?

    KANG1943 这个问题有点复杂,时间所限,我只能简短回复一下。你的猜测基本是对的。在 Windows 上用 R 处理多字节字符时,最好是将系统区域格式设置中的非 Unicode 程序语言设置为你要处理的语言,比如这里的日语。界面语言可以不设置为日语,但在 R 里要用 Sys.setlocale() 设置日语;如果界面语言也设置为日语的话,就不用 Sys.setlocale() 了。

    这是因为 R 在 Windows 上会将字符编码转化为原生编码,你用 options('encoding') 看就知道它的默认值是 native.enc。如果系统的原生编码不支持你的语言,那么这些字符会丢失。R 的转化是用户不可控的。你只能通过调整系统编码来处理相应语言的字符。R 包 fs 不存在这个问题,你也可以考虑用它进行文件操作。基础 R 本身可能还要等几年才能填上这个已经存在多年的大坑了:https://developer.r-project.org/Blog/public/2020/07/30/windows/utf-8-build-of-r-and-cran-packages/index.html 你也可以尝尝鲜,看 Tomas Kalibera 编的那个开发版本的 R 是否可用。

    KANG1943 通过改变电脑非Unicode程序语言设置和Sys.setlocale()实现正确读取的方法会不会有什么副作用?比如在后续读取其他语言的数据、数据文件或文件名的时候是否会出问题?

    这个我只能凭经验说,应该不会。把系统语言调成日语的话,肯定还能处理英语字符;但反过来就不行。前者的字符集合远大于后者。如果你经常需要处理日语数据,建议还是把系统改成日语的。当然,如果能不用 Windows,那这个坑也就不存在了。苹果和 Linux 都是原生支持 UTF-8。