メモ:RcppでCharacterMatrixをUTF-8に変換する

なんとなくわかった気がする(気のせい)。Dirkの例はだいたいstd::transform()を使っているのでこれを真似する。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
String enc2utf8_string(const String & x) {
  String str(x);
  str.set_encoding(CE_UTF8);
  return str;
}

// [[Rcpp::export]]
CharacterVector enc2utf8_chrvec(const CharacterVector & x) {
  CharacterVector str(x.size());
  std::transform(x.begin(), x.end(), str.begin(), enc2utf8_string);
  return str;
}

// [[Rcpp::export]]
CharacterMatrix enc2utf8_chrmtx(const CharacterMatrix & x) {
  CharacterMatrix str(x.nrow(), x.ncol());
  std::transform(x.begin(), x.end(), str.begin(), enc2utf8_string);
  return str;
}

でも、津駄さんのIntroduction to Rcppを見ながらラムダ式が使えるかやってたけど、なんかエラーになる。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::export]]
CharacterVector enc2utf8_chrvec2(const CharacterVector & x) {
  CharacterVector str(x.size());
  std::transform(x.begin(), x.end(), str.begin(),
                 [](String & s){ s.set_encoding(CE_UTF8); });
  return str;
}
C:/Rtools/mingw_64/x86_64-w64-mingw32/include/c++/bits/stl_algo.h:4164:33: note: void (*)(Rcpp::String&) <conversion>
  *__result = __unary_op(*__first);
                                 ^
C:/Rtools/mingw_64/x86_64-w64-mingw32/include/c++/bits/stl_algo.h:4164:33: note:   candidate expects 2 arguments, 2 provided
test.cpp:31:31: note: enc2utf8_chrvec2(const CharacterVector&)::<lambda(Rcpp::String&)>
                  [](String & s){ s.set_encoding(CE_UTF8); });
                               ^
test.cpp:31:31: note:   no known conversion for argument 1 from 'Rcpp::internal::const_string_proxy<16>' to 'Rcpp::String&'
make: *** [test.o] Error 1

このへんのなんとかproxyみたいな仕組みがよくわからない…。


追記(2017/3/23):

この挙動はいったい…。うーん。

Encoding(enc2utf8_string("あ"))
#> [1] "UTF-8"
Encoding(enc2utf8_string("a"))
#> [1] "unknown"

追記(2017/3/25):

コメント欄で教えてもらったけど、constにしたらいけました。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::export]]
CharacterVector enc2utf8_chrvec2(const CharacterVector & x) {
  CharacterVector str(x.size());
  std::transform(x.begin(), x.end(), str.begin(),
                 [](const String & s){
                    String t(s);
                    t.set_encoding(CE_UTF8);
                    return t; });
  return str;
}

この挙動はいったい…。うーん。

これは、r-wakalangで教えてもらいましたが、意図した挙動とのこと。

Only CE_UTF8 and CE_LATIN1 are marked on CHARSXPs (and so Rf_getCharCE will only return one of the first three), and these should only be used on non-ASCII strings. (http://www.hep.by/gnu/r-patched/r-exts/R-exts_125.html)

素のRの関数でも同じ挙動でした。

Encoding(enc2utf8("あ"))
#> [1] "UTF-8"
Encoding(enc2utf8("a"))
#> [1] "unknown"