【发布时间】: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++ 很陌生,但我理解在 rcpp 和 StringVector res(10); 中创建一个向量的想法(创建一个长度为 10 的名为 res 的向量),然后我可以索引 res[1] = "blah"。
我的问题是 - 如何获取 boost::xpressive::sregex_token_iterator begin( input.begin(), input.end(), re ,-1), end; 的输出并将其存储在向量中以便我可以返回它?
最终可行的 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<string>上使用back_inserter并在结果上调用Rcpp::wrap;例如std::vector<std::string> result; std::copy(begin, end, std::back_inserter(result)); return Rcpp::wrap(result);. -
@Mark 那
tokenize函数需要重写。连接你已经拥有的字符串是没有意义的,你甚至不需要x复制那里;你制作了 t 和 v 的无用副本,并且使用索引z而不是const iterator进行迭代至少在这里是可疑的,因为你只是将它用于取消引用。