【问题标题】:Rcpp - Capture result of sregex_token_iterator to vectorRcpp - 将 sregex_token_iterator 的结果捕获到向量
【发布时间】:2015-11-03 21:32:43
【问题描述】:

我是 R 用户,正在学习 c++ 以在 Rcpp 中加以利用。最近,我在 Rcpp 中使用 string.h 编写了 R 的 strsplit 的替代方案,但它不是基于正则表达式的(afaik)。我一直在阅读有关 Boost 的文章并找到了 sregex_token_iterator。

下面的网站有一个例子:

std::string input("This is his face");
sregex re = sregex::compile(" "); // find white space

// iterate over all non-white space in the input. Note the -1 below:
sregex_token_iterator begin( input.begin(), input.end(), re, -1 ), end;

// write all the words to std::cout
std::ostream_iterator< std::string > out_iter( std::cout, "\n" );
std::copy( begin, end, out_iter );

我的rcpp 函数运行良好:

#include <Rcpp.h>
#include <boost/xpressive/xpressive.hpp>
using namespace Rcpp;

// [[Rcpp::export]]
StringVector testMe(std::string input,std::string uregex) {
  boost::xpressive::sregex re = boost::xpressive::sregex::compile(uregex); // find a date

  // iterate over the days, months and years in the input
  boost::xpressive::sregex_token_iterator begin( input.begin(), input.end(), re ,-1), end;

  // write all the words to std::cout
  std::ostream_iterator< std::string > out_iter( std::cout, "\n" );
  std::copy( begin, end, out_iter );
  return("Done");
}

/*** R
testMe("This is a funny sentence"," ")
*/

但它所做的只是打印出令牌。我对 C++ 很陌生,但我理解在 rcppStringVector res(10); 中创建一个向量的想法(创建一个长度为 10 的名为 res 的向量),然后我可以索引 res[1] = "blah"

我的问题是 - 如何获取 boost::xpressive::sregex_token_iterator begin( input.begin(), input.end(), re ,-1), end; 的输出并将其存储在向量中以便我可以返回它?

http://www.boost.org/doc/libs/1_54_0/doc/html/xpressive/user_s_guide.html#boost_xpressive.user_s_guide.string_splitting_and_tokenization


最终可行的 Rcpp 解决方案

包括这个是因为我的需求是特定于 Rcpp 的,我必须对所提供的解决方案进行一些小改动。

#include <Rcpp.h>
#include <boost/xpressive/xpressive.hpp>

typedef std::vector<std::string> StringVector; 
using boost::xpressive::sregex; 
using boost::xpressive::sregex_token_iterator;
using Rcpp::List;

void tokenWorker(/*in*/      const std::string& input, 
                 /*in*/      const sregex re,
                 /*inout*/   StringVector& v) 
{
  sregex_token_iterator begin( input.begin(), input.end(), re ,-1), end;

  // write all the words to v
  std::copy(begin, end, std::back_inserter(v));
}

//[[Rcpp::export]]
List tokenize(StringVector t, std::string tok = " "){
  List final_res(t.size());
  sregex re = sregex::compile(tok); 
  for(int z=0;z<t.size();z++){

    std::string x = "";

    for(int y=0;y<t[z].size();y++){
      x += t[z][y];
    }

    StringVector v;
    tokenWorker(x, re, v);
    final_res[z] = v;
  }
  return(final_res);
}

/*** R
tokenize("Please tokenize this sentence")
*/

【问题讨论】:

  • 您可以在vector&lt;string&gt; 上使用back_inserter 并在结果上调用Rcpp::wrap;例如std::vector&lt;std::string&gt; result; std::copy(begin, end, std::back_inserter(result)); return Rcpp::wrap(result);.
  • @Mark 那tokenize 函数需要重写。连接你已经拥有的字符串是没有意义的,你甚至不需要 x 复制那里;你制作了 t 和 v 的无用副本,并且使用索引 z 而不是 const iterator 进行迭代至少在这里是可疑的,因为你只是将它用于取消引用。

标签: c++ r boost rcpp


【解决方案1】:

我的问题是 - 我如何获取 boost::xpressive::sregex_token_iterator begin(input.begin(), input.end(), re ,-1), 结束;并将其存储在向量中,以便我可以返回 是吗?

你已经成功了一半。

缺少的链接只是std::back_inserter

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <boost/xpressive/xpressive.hpp>

typedef std::vector<std::string> StringVector; 
using boost::xpressive::sregex; 
using boost::xpressive::sregex_token_iterator; 


void testMe(/*in*/      const std::string& input, 
            /*in*/      const std::string& uregex,
            /*inout*/   StringVector& v) 
{
    sregex re = sregex::compile(uregex); 

    sregex_token_iterator begin( input.begin(), input.end(), re ,-1), end;

    // write all the words to v
    std::copy(begin, end, std::back_inserter(v));
}

int main() 
{

    std::string input("This is his face");
    std::string blank(" ");
    StringVector v;
     // find white space
    testMe(input, blank, v);

    std::copy(v.begin(), v.end(), 
              std::ostream_iterator<std::string>(std::cout, "|"));

    std::cout << std::endl;
    return 0;
}

输出:

This|is|his|face|

我使用的是旧版 C++,因为您使用了来自 boost 的正则表达式库,而不是 std &lt;regex&gt;;当你现在学习 c++ 时,也许你最好从一开始就考虑 C++14; C++14 甚至会缩短这个小的 sn-p 并使其更具表现力。

【讨论】:

  • 感谢旧版 c++ - Rcpp 支持 C++11,但我认为它不支持 C++14。所以我正在研究std::back_inserter 以及如何实现它。与我尝试做的不同之处在于我需要返回 StringVector,因为这实际上将作为 R 中使用的函数进行编译。我收到一条难以理解的错误消息:“没有可行的重载 '=' " 指向一个_tree 文件。
  • @Mark 但你确定它支持 C++11?如果是这样,我会很高兴更新它;这不是什么大不了的事,而是一个很大的进步。 .
  • @Mark:并不是我忘记了它——当然,你可以返回一个 StringVector 而不是将它作为 /*inout*/ 参数传递。但是对于返回值实际会发生什么以及是否以及为什么会或不会是 Legacy C++ 中的(可能是昂贵的)副本,有一点需要了解。搜索“返回值优化”(RVO)
  • 是的,我确信它支持 C++11,尽管我几乎不明白这意味着什么。我正在做的是创建一个在 C++ 中编译但通过 R 中的库可以从 R 调用的函数。这样做是为了提高经常重用或昂贵函数的性能。我需要接受一个字符串,解析它并返回一个 StringVector。看来您已经给了我执行此操作的工具(我提到的错误在某些情况下会消失,所以我想我已经解决了)。
  • Rcpp 支持你的编译器支持的任何东西——比如说,如果你有 g++ 5.2,你可以打开 C++14。我们确实在 CRAN 包中大量使用了 C++11。但是,是的,一旦 C++14 变得更普遍,生活会变得更轻松,因为缺少正则表达式库会很痛苦。
【解决方案2】:

这里是 C++11 版本。

除了使用标准化&lt;regex&gt; 的好处之外,&lt;regex&gt;-using 版本的编译速度大约是使用 gcc-4.9 和 clang-3.5 (-g -O0 -std=) 的 boost::xpressive 版本的两倍c++11) 在运行 Debian x86_64 Jessie 的 QuadCore-Box 上。

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

//////////////////////////////////////////////////////////////////////////////
// A minimal adaption layer atop boost::xpressive and c++11 std's <regex>   //
//--------------------------------------------------------------------------//
// remove the comment sign from the #define if your compiler suite's        //
// <regex> implementation is not complete                                   //
//#define USE_REGEX_FALLBACK_33509467 1                                     //
//////////////////////////////////////////////////////////////////////////////
#if defined(USE_REGEX_FALLBACK_33509467)
#include <boost/xpressive/xpressive.hpp>
using regex = boost::xpressive::sregex; 
using sregex_iterator = boost::xpressive::sregex_token_iterator; 

auto compile = [] (const std::string& s) { 
    return boost::xpressive::sregex::compile(s);
}; 

auto make_sregex_iterator = [] (const std::string& s, const regex& re) {
    return sregex_iterator(s.begin(), s.end(), re ,-1);
};    

#else // #if !defined(USE_REGEX_FALLBACK_33509467)

#include <regex>
using regex = std::regex; 
using sregex_iterator = std::sregex_token_iterator; 

auto compile = [] (const std::string& s) { 
    return regex(s); 
}; 

auto make_sregex_iterator = [] (const std::string& s, const regex& re) {
    return std::sregex_token_iterator(s.begin(), s.end(), re, -1);
};    

#endif // #if defined(USE_REGEX_FALLBACK_33509467)
//////////////////////////////////////////////////////////////////////////////


typedef std::vector<std::string> StringVector; 


StringVector testMe(/*in*/const std::string& input, 
                    /*in*/const std::string& uregex)
{
    regex re = compile(uregex); 

    sregex_iterator begin = make_sregex_iterator(input, re), 
                    end;

    return StringVector(begin, end); // doesn't steal the strings
                                     // but try (and succeed) to move the vector
}

int main() {
    std::string input("This is his face");
    std::string blank(" ");

     // tokenize by white space
    StringVector v = testMe(input, blank);

    std::copy(v.begin(), v.end(), 
              std::ostream_iterator<std::string>(std::cout, "|"));

    std::cout << std::endl;

    return EXIT_SUCCESS;
}

【讨论】:

  • 谢谢。我使用&lt;regex&gt; 版本(无提升)在Rcpp 中构建了它,该版本的函数运行速度比C++ 解决方案慢12 倍。使用 boost 使它们具有可比性,但没有 C++11 的明显速度优势。
  • @Mark 这里的“运行”是什么意思 - 编译器“运行”多长时间或函数在运行时“运行”多长时间?请始终说明编译器版本和使用的选项以及有关性能的声明。
  • 我引用的数字是从 R 编译后调用的运行时执行。我将尝试找出编译器版本和选项并发布它们。
  • @decltype_ato 这是我在编译器窗口中看到的 clang++ -std=c++11 -I/Library/Frameworks/R.framework/Resources/include -DNDEBUG -I/usr/local/包括 -I/usr/local/include/freetype2 -I/opt/X11/include -DPLATFORM_PKGTYPE='"mac.binary.mavericks"' -I"/Library/Frameworks/R.framework/Versions/3.2/Resources/library /Rcpp/include"-I"/Users/mark/Documents/R Projects/rcpp Workshop" -fPIC -Wall -mtune=core2 -g -O2 -c second_attempt.cpp -o second_attempt.o
  • clang++ -std=c++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/ local/lib -o sourceCpp_12.so second_attempt.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
猜你喜欢
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 2012-12-24
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 2012-05-13
  • 1970-01-01
相关资源
最近更新 更多