knitr:从块生成UTF-8输出

时间:2017-05-12 11:17:57

标签: r encoding utf-8 knitr

我有一个doc.Rnw应该产生一些俄语UTF-8字符串:

\documentclass{article}
\usepackage{inputenc}
\inputencoding{utf8}
\usepackage[main=english,russian]{babel}
\begin{document}
\selectlanguage {russian} 
<<test, results='asis', echo=FALSE>>=
print(readLines('string.rus', encoding="UTF-8"))

print("Здравствуйте")
@

Здравствуйте
\selectlanguage {english}
\end{document}

string.rus有一个UTF-8字符串,可在R控制台中显示:

print(readLines('string.rus', encoding="UTF-8"))    
# [1] "Здравствуйте"

doc.Rnw在Windows记事本中同时显示,而两者都是:

file.show("doc.Rnw")
file.show("doc.Rnw", encoding="UTF-8")

无法正确显示UTF-8字符串。

使用:

knit("doc.Rnw")

输出doc.tex的文档部分显示:

\begin{document}
\selectlanguage {russian} 
[1] "<U+0417><U+0434><U+0440><U+0430><U+0432><U+0441><U+0442><U+0432><U+0443><U+0439><U+0442><U+0435>"
[1] " <U+0097>д <U+0080>авс <U+0082>в <U+0083>й <U+0082>е"


Здравствуйте
\selectlanguage {english}
\end{document}

当然不能在PDFLaTeX中编译。使用:

knit("doc.Rnw", encoding="UTF-8")

给出了更糟糕的结果。

评论应该生成UTF-8字符串的块:

print(readLines('string.rus', encoding="UTF-8"))     
print("Здравствуйте")

给出一个有效的doc.tex,它在MikTeX中编译并正确显示剩余的UTF-8字符串。
即使我评论第一个print...而只留下第二个doc.Rnw。我无法编译。这似乎证明了print的原始编码是正确的。

我尝试将两个a="Здравствуйте" Encoding(a)="UTF-8" print(a) 命令替换为:

[1] «U+0417><U+0434><U+0440><U+0430><U+0432><U+0441><U+0442><U+0432><U+0443>
Здравствуйте

在这种情况下,我可以编译,但PDF输出是(第一个字符串是从边距切出):

<?php
$statement = $this->db->prepare('
SELECT `Activity`, `Result`, `Time`
FROM `user_activity`
WHERE `Activity` LIKE :A AND `Time` BETWEEN :CM AND :NM AND `Result` = :R AND `UserId` = :ID;');
$statement->execute(
[
    ':A' => "%".$_POST['A']."%",
    ':CM' => "2017-".$_POST['CM']."-01",
    ':NM' => "2017-".($_POST['CM'] + 1)."-01",
    ':R' => $_POST['R'],
    ':ID' => $_POST['ID']
]);

所以块输出仍然是错误的。

如何从块中正确打印UTF-8字符串?
R版本为3.3.3(2017-03-06)for Windows,knitr为1.15.1(2016-11-22)。

1 个答案:

答案 0 :(得分:1)

以下是一个扩展的工作示例:

\documentclass{article}
\usepackage{inputenc}
\inputencoding{utf8}
\usepackage[main=english,russian]{babel}
\begin{document}
\selectlanguage {russian} 
<<test, results='asis', echo=FALSE>>=

s=readLines('string.rus', , encoding="UTF-8")
message("s ", Encoding(s), ": ", s)
Encoding(s)="latin1"
message("s latin1: ", s)
Encoding(s)="unkwnown"
message("s unkwnown: ", s)
Encoding(s)="utf8"
message("s utf8: ", a)


a="Здравствуйте"
message("a ", Encoding(a), ": ", a)
Encoding(a)="latin1"
message("a latin1: ", a)
Encoding(a)="utf8"
message("a utf8: ", a)
Encoding(a)="UTF-8"
message("a UTF-8: ", a)

u=("\U0417")
message("u ", Encoding(u), ": ", u)
Encoding(u)="latin1"
message("u latin1: ", u)
Encoding(u)="unkwnown"
message("u unkwnown: ", u)

@

Здравствуйте
\selectlanguage {english}
\end{document}

knit("doc.Rnw"之后,这是与test中找到的doc.tex块相关的输出(为了便于阅读,没有编码器代码装饰):

s UTF-8: <U+0417><U+0434><U+0440><U+0430><U+0432><U+0441><U+0442><U+0432><U+0443><U+0439><U+0442><U+0435>

s latin1: Здравствуйте

s unkwnown: Здравствуйте

s utf8: <U+0417><U+0434><U+0440><U+0430><U+0432><U+0441><U+0442><U+0432><U+0443><U+0439><U+0442><U+0435>

a unknown: Здравствуйте

a latin1: Здравствуйте

a utf8: Здравствуйте

a UTF-8: <U+0417><U+0434><U+0440><U+0430><U+0432><U+0441><U+0442><U+0432><U+0443><U+0439><U+0442><U+0435>

u UTF-8: <U+0417>

u latin1: З

u unkwnown: З

一些评论如下。

首先,只有message()有效,print()总是会出错。

在外部读取的字符串s和本地设置的a中,行为都是怪异的
实际上,将代码保持或明确设置为UTF-8会产生错误的结果(utf8适用于a)。
有人可能会认为文档(doc.Rnwstring.rus)的UTF8编码没有正确设置。这就是我添加行u=("\U0417")的原因,肯定是UTF8。同样,仅删除UTF8编码可提供适当的输出。

以类似的方式,明确请求UTF8输出:

knit("doc.Rnw", encoding="UTF-8")

不会生成UTF8字符,但它们的unicode值或奇怪的值。

最后,我可以生成所需的.tex文件并编译它的LaTeX,但为什么上述反直觉行为超出了我的范围。
希望有人会给出一个很好的解释。