3

ファイルを Rcpp と共に Windows-1252 エンコーディングに読み込むときに、入力形式を強制したい。Linux/Windows 環境を切り替え、ファイルが一貫して 1252 エンコーディングであるため、これが必要です。

これを機能させるにはどうすればよいですか:

String readFile(std::string path) {
  std::ifstream t(path.c_str());
  if (!t.good()){
    std::string error_msg = "Failed to open file ";
    error_msg += "'" + path + "'";
    ::Rf_error(error_msg.c_str());
  }

  const std::locale& locale = std::locale("sv_SE.1252");
  t.imbue(locale); 
  std::stringstream ss;
  ss << t.rdbuf();
  return ss.str();
}

上記は次の場合に失敗します。

Error in eval(expr, envir, enclos) : 
  locale::facet::_S_create_c_locale name not valid

また、システムのデフォルトである「Swedish_Sweden.1252」を試してみましたが、役に立ちませんでした。試してみまし#include <boost/locale.hpp>たが、Rcpp (v 0.12.0)/BH boost (v. 1.58.0-1) では利用できないようです。

アップデート:

これをもう少し深く掘り下げた後、RTools (v. 3.3) の gcc (v. 4.6.3) がロケールをサポートして構築されているかどうかはわかりません。この SO の質問はその可能性を示しています。"" または "C" 以外の引数が std::locale() で機能する場合、それを知ることは興味深いでしょう。さらにいくつかの代替手段を試しましたが、何も機能しないようです。

フォールバック ソリューション

私は完全に満足しているわけではありませんが、base::iconv()修正を使用すると、元の形式に関係なく、文字に関する問題が修正されたようです。これは、文字を正しい形式で解釈することを強制する引数のおかげですfrom="WINDOWS-1252"。つまり、Rcpp にとどまりたい場合は、単純に行う:

String readFile(std::string path) {
  std::ifstream t(path.c_str());
  if (!t.good()){
    std::string error_msg = "Failed to open file ";
    error_msg += "'" + path + "'";
    ::Rf_error(error_msg.c_str());
  }

  const std::locale& locale = std::locale("sv_SE.1252");
  t.imbue(locale); 
  std::stringstream ss;
  ss << t.rdbuf();
  Rcpp::StringVector ret = ss.str();

  Environment base("package:base");
  Function iconv = base["iconv"];

  ret = iconv(ret, Named("from","WINDOWS-1252"),Named("to","UTF8"));

  return ret;
}

C++ から関数を取得してそこから呼び出すよりも、R で関数をラップする方が望ましいことに注意してください。コードが少なくて済み、パフォーマンスが 2 倍向上します (マイクロベンチマークで確認)。

readFileWrapper <- function(path){
   ret <- readFile(path)
   iconv(ret, from = "WINDOWS-1252", to = "UTF8")
}
4

0 に答える 0