2014-03-24 65 views
12

是否有將匹配發送給用戶的功能,然後代替返回值的正則表達式替換的功能:正則表達式替換回調在C + + 11?

我試過這種方法,但它顯然是行不通的:

cout << regex_replace("my values are 9, 19", regex("\d+"), my_callback); 

和功能:

std::string my_callback(std::string &m) { 
    int int_m = atoi(m.c_str()); 
    return std::to_string(int_m + 1); 
} 

,其結果應該是:my values are 10, 20

我的意思是類似的模式像php的preg_replace_callback或python的re.sub(pattern, callback, subject)

而我的意思是最新的4.9 gcc,這是能夠正則表達式沒有提升。

回答

14

我想要這種功能,並不喜歡答案「使用提升」。本傑明的答案的問題是它提供了所有的令牌。這意味着您不知道哪個令牌是匹配的,並且不允許您使用捕獲組。這樣做:

// clang++ -std=c++11 -stdlib=libc++ -o test test.cpp 
#include <cstdlib> 
#include <iostream> 
#include <string> 
#include <regex> 

namespace std 
{ 

template<class BidirIt, class Traits, class CharT, class UnaryFunction> 
std::basic_string<CharT> regex_replace(BidirIt first, BidirIt last, 
    const std::basic_regex<CharT,Traits>& re, UnaryFunction f) 
{ 
    std::basic_string<CharT> s; 

    typename std::match_results<BidirIt>::difference_type 
     positionOfLastMatch = 0; 
    auto endOfLastMatch = first; 

    auto callback = [&](const std::match_results<BidirIt>& match) 
    { 
     auto positionOfThisMatch = match.position(0); 
     auto diff = positionOfThisMatch - positionOfLastMatch; 

     auto startOfThisMatch = endOfLastMatch; 
     std::advance(startOfThisMatch, diff); 

     s.append(endOfLastMatch, startOfThisMatch); 
     s.append(f(match)); 

     auto lengthOfMatch = match.length(0); 

     positionOfLastMatch = positionOfThisMatch + lengthOfMatch; 

     endOfLastMatch = startOfThisMatch; 
     std::advance(endOfLastMatch, lengthOfMatch); 
    }; 

    std::regex_iterator<BidirIt> begin(first, last, re), end; 
    std::for_each(begin, end, callback); 

    s.append(endOfLastMatch, last); 

    return s; 
} 

template<class Traits, class CharT, class UnaryFunction> 
std::string regex_replace(const std::string& s, 
    const std::basic_regex<CharT,Traits>& re, UnaryFunction f) 
{ 
    return regex_replace(s.cbegin(), s.cend(), re, f); 
} 

} // namespace std 

using namespace std; 

std::string my_callback(const std::smatch& m) { 
    int int_m = atoi(m.str(0).c_str()); 
    return std::to_string(int_m + 1); 
} 

int main(int argc, char *argv[]) 
{ 
    cout << regex_replace("my values are 9, 19", regex("\\d+"), 
     my_callback) << endl; 

    cout << regex_replace("my values are 9, 19", regex("\\d+"), 
     [](const std::smatch& m){ 
      int int_m = atoi(m.str(0).c_str()); 
      return std::to_string(int_m + 1); 
     } 
    ) << endl; 

    return 0; 
} 
8

你可以使用一個regex_token_iterator

#include <iostream> 
#include <algorithm> 
#include <regex> 
#include <string> 
#include <sstream> 

int main() 
{ 
    std::string input_text = "my values are 9, 19"; 
    std::string output_text; 
    auto callback = [&](std::string const& m){ 
     std::istringstream iss(m); 
     int n; 
     if(iss >> n) 
     { 
      output_text += std::to_string(n+1); 
     } 
     else 
     { 
      output_text += m; 
     } 
    }; 

    std::regex re("\\d+"); 
    std::sregex_token_iterator 
     begin(input_text.begin(), input_text.end(), re, {-1,0}), 
     end; 
    std::for_each(begin,end,callback); 

    std::cout << output_text; 
} 

注意的是,在迭代器的構造函數的參數列表中的{-1,0}是指定我們要迭代子匹配列表過度。 -1用於不匹配的部分,而0用於第一個子匹配。

另請注意,我沒有廣泛使用C++ 11正則表達式的功能,而且我也沒有專家。所以這個代碼可能有問題。但對於您的具體輸入,我測試了它,似乎產生了預期的結果。如果您發現任何不適用的輸入設置,請讓我知道。

+0

它的工作原理。但我認爲Boost是一個更好的解決方案。 http://stackoverflow.com/questions/11508798/conditionally-replace-regex-matches-in-string – duleshi