Rcpp - 将sregex_token_iterator的结果捕获到向量

时间:2015-11-03 21:32:43

标签: c++ r boost rcpp

我是R用户,正在学习c ++以利用Rcpp。最近,我使用strsplit在Rcpp中为R&#39 {s} string.h编写了一个替代方案,但它不是基于regex(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 ++的新手,但我理解在rcpp中使用StringVector res(10);制作一个向量的想法(制作一个名为res的长度为10的向量)然后我可以将其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")
*/

2 个答案:

答案 0 :(得分:5)

  

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

你已经到了一半了。

缺失的链接只是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 <regex>的正则表达式lib;也许你现在就学习c ++,从一开始就考虑更好地考虑C ++ 14; C ++ 14甚至可以缩短这个小片段并使其更具表现力。

答案 1 :(得分:0)

这是C ++ 11版本。

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

#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;
}