std::regex_replace 替换 n 个出现并获取替换次数

std::regex_replace replace n occurences and get number of substitutions

本文关键字:替换 获取 regex replace std      更新时间:2023-10-16

我正在使用std::regex_replace来修改字符串。我既需要限制替换次数,也需要完成替换的数量。

我使用了以下代码:

std::wregex rx(pattern);
size_t n = 0; // one match
size_t ns = 3;
wstring result = src;
wstring old; // old value
bool replaced = false;
do {
    old = result;
    result = std::regex_replace(result, rx, replace, std::regex_constants::format_first_only);
    replaced = result != old;
    if (replaced)
        n++;
} while (replaced && n < ns); 

它工作正常,我既可以限制替代量,也可以获取它们的数量。但是,如果我有以下值,则此代码会从头开始分析字符串:

"banana" for src, "(an)" for pattern and "$1-" for replace

它产生以下输出:ban---ana 而不是ban-an-a。显然,这是因为 std::regex_replace 从一开始就分析字符串。一种解决方案可能是使用迭代器来定义要分析的第一个字符,但在这种情况下,我需要获取指向重新加载字符之后的迭代器,但是我如何获得它?

事实证明,这比我想象的要棘手。我在这里没有发现任何std::regex_replace()功能非常有用。

我决定根据此处实现描述中建议的算法采用直接std::wsregex_iterator解决方案:

http://en.cppreference.com/w/cpp/regex/regex_replace

这就是我想出的:

#include <regex>
#include <string>
#include <iterator>
#include <iostream>
int main()
{
    std::size_t ns = 3;
    std::wstring text = L"banana";
    std::wstring pattern = L"(an)";
    std::wstring replace = L"$1-";
    std::wstring result;
    std::wregex rx(pattern);
    auto iter = std::wsregex_iterator(text.begin(), text.end(), rx);
    auto stop = std::wsregex_iterator();
    auto last_iter = iter;
    auto out = std::back_inserter(result);
    for(std::size_t n = ns; n-- && iter != stop; ++iter)
    {
        out = std::copy(iter->prefix().first, iter->prefix().second, out);
        out = iter->format(out, replace);
        last_iter = iter;
    }
    out = std::copy(last_iter->suffix().first, last_iter->suffix().second, out);
    std::wcout << "  text: " << text << 'n';
    std::wcout << "result: " << result << 'n';
}

输出:

  text: banana
result: ban-an-a

您可以设置计数器并使用回调。这只会替换您设置的最大值。
(未经测试)

static int REPL_count = 0;
static int REPL_max = 0;
static string REPL_replace = "";

string REPLcallback( const wsmatch m )
{
    // Return formatted match if under the max count
    if ( REPL_count < REPL_max )
    {
        ++REPL_count;
        return m.format( REPL_replace );
    }
    // Exceeded count, just return match without formatting
    return string(m[0].first, m[0].second);
}
int ReplaceText(
         string& strIn,
         string& strOut,
         wregex  Regex,
         string& strReplacement,
         int     max )
{
    REPL_count = 0;
    REPL_max = max;
    REPL_replace = strReplacement;
    strOut = regex_replace( strIn, Regex, REPLcallback );
    return REPL_count;
}