第6章 その他
6.1 パッケージ内で日本語を使う
Rのパッケージに非ASCII文字を含めることは推奨されない。だが可能だ。
具体的には、DESCRIPTION
にEncoding
を指定しつつ、
\uXXXX
のエスケープを使う- データに含める
- メッセージ翻訳の仕組みを使う
のいずれかの手を使う。
6.1.1 DESCRIPTION
Encoding
フィールドにUTF-8
を指定する。これはおそらくいずれの手を使うにしても必要なはず。
Encoding: UTF-8
あと、Writing R Extensionsによると、厳密には、
Depends:
R (>= 2.10)
も指定しないといけないらしい。
6.1.2 \uXXXX
のエスケープを使う
これがR Packagesが推奨している方法3。
stringi::stri_escape_unicode()
を使うとエスケープされた文字列を知ることができる。たとえば、「あ」という文字列を使いたいなら、
cat(stringi::stri_escape_unicode("あ"))
## \u3042
ということで、"あ"
の代わりに"\u3042"
と書けばいい。UTF-8になっているので、デフォルトの文字コードと合わせたいならenc2native()
する必要がある点に注意。
6.1.3 データに含める
UTF-8にした文字列をデータとしてパッケージに含める、という手もある。 ただし、これは最近、CRAN checkの結果に
Result: NOTE
Note: found 52458 marked UTF-8 strings
という表示が出るのが気になる。いずれ使えなくなる?
6.1.4 メッセージの翻訳の仕組みを使う
あまり使われているのを見かけないが、Rにはメッセージの翻訳の仕組みがある4。 日本語を含めたい理由がメッセージを表示させるためであれば、これを使う手もある。具体的には、以下の流れになる。
tools::update_pkg_po(".")
を実行する。ソースコード中のstop()
、warning()
、message()
のメッセージを読み取ってpo/R-パッケージ名.pot
というメッセージ翻訳のテンプレートができる。- テンプレートファイルをコピーして
po/R-ja.po
(またはpo/ja.po
)というファイルをつくる。 inst
下にインストールする5 。Windowsの場合あらかじめgettext
のインストールが必要6 。
mkdir -p inst/po/ja/LC_MESSAGES
msgfmt -c --statistics -o inst/po/ja/LC_MESSAGES/R-パッケージ名.mo po/R-ja.po
なお、翻訳の仕組みを使う場合、stop()
等にはdomain = "R-パッケージ名"
を指定しておいた方が無難。
6.2 dynamic registeration of S3 method
6.3 Rcpp
6.4 C
「Advanced R」のCの関数についての章はまだ第二版にはないのでひとまず第一版を参照。
6.4.1 ヘッダファイル
Cの関数を使えるようにするには以下のヘッダをincludeする。
#include <R.h>
#include <Rinternals.h>
6.4.1.1 R_NO_REMAP
we recommend that you use
R_NO_REMAP
so all API functions have the prefixR_
orRf_
とあるが、これをdefineするとallocVector()
やasReal()
のような関数も動かなくなってしまうので注意。
6.4.1.2 USE_RINTERNALS
R Internals(公式)によれば、
The only way to obtain direct access to the internals of the
SEXPREC
s is to define'USE_RINTERNALS'
before including header fileRinternals.h
,
とある。rlangとかdplyrでも使ってないので、たぶん必要になることはなさそう。
6.4.2 関数の登録
Rcppと違って、Cの関数は自分で登録しないといけない。具体的には、init.c
みたいなやつを作って以下を書く。
例えばSEXP foo(SEXP, SEXP);
というCの関数を別ファイルで定義しているとすると、以下のようになる。
なお、R_registerRoutines()
あたりについては、R 3.4以降のことなのでAdvanced R第1版にも載っていない。
Registering Routines with Rcppあたりを参考のこと(うまく説明できない)。
#include "./foo.h"
// TODO: これはincludeしなくてもコンパイルできたので要らないのかも
#include <R_ext/Rdynload.h>
// 同名・同じシグネチャの関数をexternで定義する
extern SEXP foo(SEXP, SEXP);
// R_registerRoutines()で関数を登録するためのエントリ
static const R_CallMethodDef CallEntries[] = {
{"foo", (DL_FUNC) &foo, 2}, // 最後の数字は引数の数
{NULL, NULL, 0} // 最後にこのNULLのエントリを入れるのがお作法っぽい
};
// 関数名はR_init_<DLL名>にする。<DLL名>は@useDynLibに指定するもの
void R_init_foo(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
あと、Rの側では、以下のように@useDynLib
を指定しておく必要がある。
#' @useDynLib foo, .registration = TRUE
6.5 ALTREP
6.5.1 C++でALTREPを使う
<R_ext/Altrep.h>
はR 3.5.xの時点ではC++に対応していない。r-develでの指摘7 を受けて修正が入った8 のでR 3.6.0以降で使うには問題ない。
Romain François氏によれば、以下のようにすればいいらしい9。
#if R_VERSION < R_Version(3, 6, 0)
#define class klass
extern "C" {
#include <R_ext/Altrep.h>
}
#undef class
#else
#include <R_ext/Altrep.h>
#endif
より長いバージョンは以下のレポジトリを参照。
6.6 Apache Arrow
https://www.stats.ox.ac.uk/pub/Rtools/goodies/gettext-tools.zip を
C:\Rtools\bin
以下に展開すればいい↩https://stat.ethz.ch/pipermail/r-devel/2018-October/076952.html↩
https://github.com/wch/r-source/commit/14365e4419d08ced8e987d5d49b26843d1324297↩
https://stat.ethz.ch/pipermail/r-devel/2018-October/076963.html↩