• R语言
  • Ubuntu 下 R Markdown 生成 PDF 文档里部分中文字符的乱码问题

Ubuntu 20.04.2 LTS 系统,R markdown 生成 pdf 文档,部分中文字符出现乱码。下面这个. Rmd 文件,出来的 pdf,最后两个字显示为 FF

---
documentclass: ctexart
output:
  rticles::ctex:
    keep_tex: yes
---

下面二字显示不出来:皞觍

查看了中间步骤生成的 .tex 文件,里面的字符是正常的。同一 Rmd 文件在 Windows 下可以正常生成 pdf。我觉得可能是 Ubuntu 下中文字体的缘故,但不知道怎么处理。

这件事的背景是我在编译《现代统计图形》印刷版,最近所有包升了级,kableExtra 包的一个问题导致我在 Windows 下无法正常编译。于是切换到不熟的 Ubuntu 下,就出现了本文提出的问题。

> sessionInfo()
R version 4.0.3 (2020-10-10)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.2 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0

locale:
 [1] LC_CTYPE=en_HK.UTF-8       LC_NUMERIC=C               LC_TIME=en_GB.UTF-8        LC_COLLATE=en_HK.UTF-8     LC_MONETARY=en_GB.UTF-8   
 [6] LC_MESSAGES=en_HK.UTF-8    LC_PAPER=en_GB.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

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.1.1 tools_4.0.3       rticles_0.18      yaml_2.2.1        rmarkdown_2.6     knitr_1.31       
 [8] xfun_0.20         digest_0.6.27     rlang_0.4.10      evaluate_0.14  

PS: 勉强找到了个解决方案,就是把 Ubuntu 下编译(绕开 kableExtra 在 Windows 里的问题)出来的 .tex 复制到 Windows 下继续编译(绕开 Ubuntu 下字体的问题)成 pdf,算是活过来了。

    dapengde 可能是 Ubuntu 下的中文字体字符集里缺字。

    我去顶了一下那个 kableExtra 问题的帖子,看看朱昊能否解决吧,感觉应该不会是很难的问题(不行就召唤和我一样为字符编码而白头的壮士 @shrektan )。

    确实是字体问题。

    ---
    documentclass: ctexart
    output:
      rticles::ctex:
        keep_tex: yes
        includes:
          in_header: "header.tex"
    ---
    
    下面二字显示出来:皞觍

    header.tex 文件内容如下:

    \setCJKmainfont[BoldFont={SimHei},ItalicFont={KaiTi}]{SimSun}
    xfun::session_info()
    R version 4.0.4 (2021-02-15)
    Platform: x86_64-pc-linux-gnu (64-bit)
    Running under: Ubuntu 20.04.2 LTS, RStudio 1.4.1103
    
    Locale:
      LC_CTYPE=zh_CN.UTF-8       LC_NUMERIC=C               LC_TIME=zh_CN.UTF-8       
      LC_COLLATE=zh_CN.UTF-8     LC_MONETARY=zh_CN.UTF-8    LC_MESSAGES=zh_CN.UTF-8   
      LC_PAPER=zh_CN.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
      LC_TELEPHONE=C             LC_MEASUREMENT=zh_CN.UTF-8 LC_IDENTIFICATION=C       
    
    Package version:
      base64enc_0.1.3   compiler_4.0.4    digest_0.6.27     evaluate_0.14     glue_1.4.2       
      graphics_4.0.4    grDevices_4.0.4   highr_0.8         htmltools_0.5.1.1 jsonlite_1.7.2   
      knitr_1.31        magrittr_2.0.1    markdown_1.1      methods_4.0.4     mime_0.10        
      rlang_0.4.10      rmarkdown_2.7     rticles_0.18      stats_4.0.4       stringi_1.5.3    
      stringr_1.4.0     tinytex_0.29      tools_4.0.4       utils_4.0.4       xfun_0.21        
      yaml_2.2.1      

    2021 年 9 月27 日更新

    ---
    documentclass: ctexart
    output: rticles::ctex
    CJKmainfont: Noto Serif CJK SC
    ---
    
    下面二字显示不出来:皞觍

    系统环境

    xfun::session_info()
    #> R version 4.1.1 (2021-08-10)
    #> Platform: x86_64-pc-linux-gnu (64-bit)
    #> Running under: Ubuntu 20.04.3 LTS
    #> 
    #> Locale:
    #>   LC_CTYPE=zh_CN.UTF-8       LC_NUMERIC=C              
    #>   LC_TIME=zh_CN.UTF-8        LC_COLLATE=zh_CN.UTF-8    
    #>   LC_MONETARY=zh_CN.UTF-8    LC_MESSAGES=zh_CN.UTF-8   
    #>   LC_PAPER=zh_CN.UTF-8       LC_NAME=C                 
    #>   LC_ADDRESS=C               LC_TELEPHONE=C            
    #>   LC_MEASUREMENT=zh_CN.UTF-8 LC_IDENTIFICATION=C       
    #> 
    #> Package version:
    #>   backports_1.2.1   base64enc_0.1.3   callr_3.7.0       cli_3.0.1        
    #>   clipr_0.7.1       compiler_4.1.1    crayon_1.4.1      digest_0.6.27    
    #>   ellipsis_0.3.2    evaluate_0.14     fansi_0.5.0       fastmap_1.1.0    
    #>   fs_1.5.0          glue_1.4.2        graphics_4.1.1    grDevices_4.1.1  
    #>   highr_0.9         htmltools_0.5.2   jsonlite_1.7.2    knitr_1.33       
    #>   lifecycle_1.0.0   magrittr_2.0.1    markdown_1.1      methods_4.1.1    
    #>   mime_0.11         pillar_1.6.2      pkgconfig_2.0.3   processx_3.5.2   
    #>   ps_1.6.0          purrr_0.3.4       R.cache_0.15.0    R.methodsS3_1.8.1
    #>   R.oo_1.24.0       R.utils_2.10.1    R6_2.5.1          rematch2_2.1.2   
    #>   reprex_2.0.0      rlang_0.4.11      rmarkdown_2.10    rprojroot_2.0.2  
    #>   rstudioapi_0.13   stats_4.1.1       stringi_1.7.4     stringr_1.4.0    
    #>   styler_1.5.1      tibble_3.1.4      tinytex_0.33      tools_4.1.1      
    #>   utf8_1.2.2        utils_4.1.1       vctrs_0.3.8       withr_2.4.2      
    #>   xfun_0.25         yaml_2.2.1

    <sup>Created on 2021-09-27 by the reprex package (v2.0.0)</sup>

    是 fandol 字体缺字,Ubuntu 下 ctex 默认使用 fandol,所以出现了这个问题。Ubuntu 和 Windows的字体都是可以的:

    ---
    documentclass: ctexart
    classoption:
      # - fontset=windows
      - fontset=ubuntu
    output:
      rticles::ctex:
        keep_tex: yes
    ---
    
    下面二字显示不出来:皞觍
    > sessionInfo()
    R version 4.0.3 (2020-10-10)
    Platform: x86_64-pc-linux-gnu (64-bit)
    Running under: Ubuntu 20.10
    
    Matrix products: default
    BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
    LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
    
    locale:
     [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
     [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=zh_CN.UTF-8       LC_NAME=C                 
     [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
    
    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.1.1 tools_4.0.3       rticles_0.18      yaml_2.2.1        rmarkdown_2.7     knitr_1.31       
     [8] xfun_0.21         digest_0.6.27     rlang_0.4.10      evaluate_0.14

    如果真的遇到了 Windows 字体才有的字,可以把所有 Windows 字体复制到 Ubuntu,然后使用 fontset=windows 选项。

      谢谢楼上各位的指点!我试了大家给的代码,仍然没成功,出来的还是 FF,暂时没时间深究了,等有时间了把 Windows 字体复制到 Ubuntu 试一试。

        dapengde 本质上都是用其它字体代替。把 Windows 字体复制到 Ubuntu 绝对是一个快速解决问题的方案,当然只复制一部分就好,全部复制过去太大了,没必要。

        3 个月 后

        dapengde 不知道你那边字体问题后来是怎么解决的,最近我发现阿里巴巴推出过一款阿里巴巴普惠体,这个字体包含的汉字比较全,而且是免费的,希望对你有帮助。

          chuxinyuan 谢谢推荐。自从上回失败之后,我没有继续研究,因为 "Ubuntu 弄出 .tex + Windows 弄出 pdf"后就交稿给出版社,之后的多次修改已经不使用 LaTeX 了。

            dapengde 很遗憾,听我那个朋友说,你们提交的书稿那边貌似还要重新用 Word 排版(当然只是听朋友这么一说,未经证实),所以你们这边的书稿只要能正常显示出来就可以了,用什么字体无所谓了,之前我还在想用微软的字体可能会有侵权的问题,现在看来压根不是我们该考虑的问题。

              chuxinyuan 更改标题为「Ubuntu 下 R Markdown 生成 PDF 文档里部分中文字符的乱码问题

              chuxinyuan 哪位朋友如此神通广大!连这天知地知的事儿都知道了...

              这事儿我不想提,说多了都是泪。

                dapengde 哈哈,这事折腾的,真是春蚕到死丝方尽,蜡炬成灰了泪都没干。没想到出版社把好好的 PDF 又用 Word 重新敲了一遍,这一重录,录出一大批错误来。我都惊呆了,这不是要作者校对起来看瞎眼吗。

                  dapengde 哈哈哈,隔着两块屏幕和其间的千山万水,都能感觉到你这心里阴影面积之大啊。

                  建议写点博文吐吐槽,别憋坏了自己。上次你说被读者们骂得不想写了,这挺可惜的。我们有些同胞像河豚,轻轻一碰就鼓起来了,本能反应而已。躲开工众号,更新博客应该可以避开大部分鼓鼓的他们。

                    tctcab 对,甭管原始文档格式是啥,作者给了终稿后出版社再全部重录一遍。大鹏都要吐血了。

                      tctcab yihui LaTeX 出版社也不是完全不用,而是据说找个会 LaTeX 排版的太难,而且会很慢。这是人家的事,我就不越俎代庖了。

                      说句公道话,这书的重录错误,已经比《学 R》少多了。当年出版社对《学 R》是用 Adobe Illustrator 重新录排的,活活排了 6 个月,反复沟通无数次,错误百出,按了葫芦起了瓢,根本看不到希望,最后完全弃用,拿半年前我做的 pdf 直接印刷去了。

                      Liechi 心态不同了,岁数也大了,已经没那么多话要写在博客上。

                      4 个月 后

                      CyrusYip 今天发现 Ubuntu 20.04.3 LTS 即使设置 fontset = ubuntu仍然会报错,报错内容如下:

                      ! Package fontspec Error: The font "AR PL KaitiM GB" cannot be found.

                      后来在这里的第 9942 行代码发现了真相。代码如下:

                      \setCJKmainfont { Noto~Serif~CJK~SC } [ ItalicFont = AR~PL~KaitiM~GB ]

                      参考debian添加中文支持,果断通过安装字体解决问题:

                      sudo apt install fonts-arphic-gkai00mp

                      dapengde 关于之前我建议的把 Windows 字体复制到 Ubuntu 下或许是一个愚蠢的建议,我暂时收回这个建议。目前 Linux 系统下 fandol 字体仍然是 ctex 的默认字体,虽然官方也有意将默认字体换为思源字体,但是并不是每个 Linux 发行版都能默认载入思源字体,因此暂时也只能维持现状了。

                      但是可喜的是,我发现在显式地设置 fontset = ubuntu后,ctex 就会使用 Ubuntu 系统自带的思源宋体(Noto Serif CJK SC),但同时也得把文鼎字体(AR PL KaitiM GB) 安上。

                      另,要是 @yihui 能为 Ubuntu 用户开个小灶,当系统缺少文鼎字体时自动安装就更好了(要求是不是有点多了,呵呵)。

                        chuxinyuan 需要用 sudo 的东西开不了小灶。TinyTeX 安装在不需要管理员权限的文件夹里,所以它可以自动安装缺失的 LaTeX 包,但它无法自动安装系统包。