2015-11-03 3 views
2

Я пользователь R и изучаю C++ для использования в Rcpp. Недавно я написал альтернативу R's strsplit в Rcpp, используя string.h, но не на основе regex (afaik). Я читал о Boost и нашел sregex_token_iterator.Rcpp - Захват результата 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") 
*/ 
+1

Вы можете просто использовать 'back_inserter' на' 'вектор и вызвать' Rcpp :: wrap' на результат; например 'std :: vector результат; std :: copy (начало, конец, std :: back_inserter (результат)); return Rcpp :: wrap (result); '. – nrussell

+0

@Mark Эта функция 'tokenize' требует перезаписи.Конкатенации строк, которые у вас уже есть, бессмысленны, и вам даже не нужна эта «х» копия; u создайте бесполезные копии t и v, и итерация с индексом 'z' вместо' const iterator' здесь по крайней мере сомнительна, потому что вы используете ее только для разыменования. –

ответ

3

Мой вопрос - как же я беру выходной импульс :: Xpressive :: sregex_token_iterator начинаются (input.begin(), input.end(), повторно, -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++, потому что вы использовали регулярное выражение экспромты из усиления вместо станд <regex>; возможно, вам лучше рассмотреть C++ 14 с самого начала, когда вы изучаете C++ прямо сейчас; C++ 14 сократил бы даже этот небольшой фрагмент и сделал бы его более выразительным.

+0

Спасибо за устаревший C++ - 'Rcpp' поддерживает C++ 11, но я не думаю, что он поддерживает C++ 14. Поэтому я ищу 'std :: back_inserter' и как его реализовать. Разница с тем, что я пытаюсь сделать, - мне нужно вернуть 'StringVector', потому что это на самом деле собирается компилироваться как функция, используемая в R. Я получаю сообщение о неразборчивости:« no жизнеспособный перегружен »= ", который указывает на файл' _tree'. – Mark

+1

@Mark Но вы уверены, что поддерживает C++ 11? Если так, я буду рад обновить его; это не было бы сделкой abig, но большим улучшением. , –

+0

@Mark: Не то, чтобы я его забыл - конечно, вы могли бы вернуть 'StringVector' вместо того, чтобы передавать это как/* inout */param. Но есть немного информации о том, что на самом деле произойдет с возвращаемыми значениями, и если и почему это было бы или не было бы (возможно, дорогостоящей) копией в Legacy C++. Найдите «оптимизацию возвращаемого значения» (RVO) –

0

И вот версия C++ 11.

Помимо преимуществ использования стандартизированного <regex>, то <regex> -при версия компилирует примерно в два раза быстрее, чем повышение :: Xpressive версии с GCC-4.9 и лязг-3.5 (-g -O0 -std = C++ 11) на QuadCore-Box, работающем с Debian x86_64 Jessie.

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

Спасибо за это. Я построил это в Rcpp, используя версию '' (без повышения), и эта версия функции выполняется в 12 раз медленнее, чем решение на C++. Использование boost делает их сопоставимыми, но без видимой выгоды от скорости C++ 11. – Mark

+0

@Mark Что вы подразумеваете под «run» здесь - как долго компилятор «работает» или как долго функция «работает» во время выполнения? Всегда указывайте версию и параметры компилятора, используемые вместе с утверждениями о производительности. –

+0

номерами, на которые я ссылался, были для выполнения выполнения, вызванного из пост-компиляции R. Я попытаюсь вычислить версию и параметры компилятора и опубликовать их. – Mark

Смежные вопросы