簡體   English   中英

替換字符串中相同正則表達式的多個匹配項

[英]Replacing multiple matches of the same regex in a string

我對std::regex的所有東西都是新手。 我試圖編寫代碼來替換下面DEFAULTS_SS_MARKER_REGEX中定義的某種模式。

我可以做一次。 當我試圖弄清楚如何替換該模式的多個實例時,問題就出現了。

源字符串可能僅包含模式的一個實例,或與模式匹配的完全相同文本的多個實例,或與模式匹配的不同文本的多個實例,或最后兩種情況的組合。

我卡住的地方是如何替換,同時忽略之前匹配和替換的文本。

我想知道在字符串中多次替換這些“標記”來實現我需要做的最好方法是什么?

嘗試編碼

using std::regex_match, std::regex_replace, std::regex;

const char * DEFAULTS_SS_MARKER_REGEX = R"(\$\{([\w ._-]+):([\w ._-]+):([\w ._-]+)\})";
#pragma region Sample Matches
/*
${Spreadsheet:Sheet:key}
${Hello1:b2:c3}
${Hello1.scss:b2:c3}
${Hello1_-scss:b2:c3}
abc${Hello1:b2:c3}def
${a:b:c}
*/
#pragma endregion Sample Matches


// first attempt, got stuck
std::string r = "${abc:def:ghi} and ${123:456:789} and ${abc:def:ghi}"; // test string to replace
bool checkForMoreMatches = true;
while (checkForMoreMatches) {
    std::cmatch m;
    auto x = regex_search(r.c_str(), m, regex(DEFAULTS_SS_MARKER_REGEX, regex::icase), std::regex_constants::match_default);
    if (m.size() == 4) {
        auto spreadsheet = m[1].str();
        auto sheet       = m[2].str();
        auto key         = m[3].str();
        std::string zz = lookup(spreadsheet, sheet, key);
        r = regex_replace(r, regex(DEFAULTS_SS_MARKER_REGEX, regex::icase), zz);
    } else checkForMoreMatches = m.size();
}

// second attempt at writing it, got stuck

// Default Spreadsheet Marker
std::string r = "${abc:def:ghi} and ${123:456:789} and ${abc:def:ghi}"; // test string to replace
std::smatch m;
while (std::regex_search(r, m, regex(DEFAULTS_SS_MARKER_REGEX, regex::icase))) {
    if (m.size() == 4) {
        auto spreadsheet = m[1].str();
        auto sheet = m[2].str();
        auto key = m[3].str();
        std::string zz = lookup(spreadsheet, sheet, key);
        r = regex_replace(r, regex(DEFAULTS_SS_MARKER_REGEX, regex::icase), zz);
    }
}

// lookup function used by all attempts
std::string lookup(std::string spreadsheet, std::string sheet, std::string key) {
    // some placeholder code, the real code would lookup a value from a spreadsheet 
    return "ss=" + spreadsheet + ",sheet=" + sheet + ",key=" + key; 
}

后記

@sigma 創建了一些非常好的短代碼,不幸的是它對我不起作用,但根據示例查找函數確實可以正常工作(假設其中的注釋被忽略)

不幸的是,這個示例查找並不能真正測試他替換原來的新代碼(一旦我告訴他它不適合我的情況)

因此,我在這里包含了一個 original-sigma-breaker 查找函數,以防將來有人感興趣。

我還包括我的完整測試代碼,包括 sigma 的原始答案和新答案。

#include <regex>
#include <iostream>

// This code answered by sigma to my question here:
// [c++ - Replacing multiple matches of the same regex in a string - Stack Overflow](https://stackoverflow.com/questions/72763724/replacing-multiple-matches-of-the-same-regex-in-a-string/72764911#72764911)

#pragma region Lookup functions

// lookup function for sigma's original code (see my comment // sigma's original code but not good for our needs (see my comment https://stackoverflow.com/a/72764911/270143))
std::string lookup(std::string spreadsheet, std::string sheet, std::string key) {
    // some placeholder code, the real code would lookup a value from a spreadsheet 
    return "ss=" + spreadsheet + ",sheet=" + sheet + ",key=" + key;
}

std::string upper(const std::string& str)
{
    std::string upper;
    transform(str.begin(), str.end(), std::back_inserter(upper), toupper);
    return upper;
}

// lookup function I devised that will break sigma's original code
std::string lookupUpper(std::string spreadsheet, std::string sheet, std::string key) {
    // some placeholder code, the real code would lookup a value from a spreadsheet 
    return "ss=" + upper(spreadsheet) + ",sheet=" + upper(sheet) + ",key=" + upper(key);
}

#pragma endregion Lookup functions

#pragma region Sigmas original answer

// sigma's original code but not good for our needs (see my comment https://stackoverflow.com/a/72764911/270143)
void testDefaultsSpreadsheetFieldMarkersReplaceSimpleLookup()
{
    std::regex markers{ R"(\$\{([\w ._-]+):([\w ._-]+):([\w ._-]+)\})", std::regex::icase };
    const std::string s = "${abc:def:ghi} and ${123:456:789} and ${abc:def:ghi}";
    std::string q = s;
    std::string r = s;

    // The trick here is the special syntax accepted by the "fmt" argument:
    // it will replace $n by the nth capture group
    std::cout << "SIGMA ORIGINAL ANSWER with Original Lookup" << std::endl;
    std::cout << std::regex_replace(q, markers, lookup("$1", "$2", "$3")) << std::endl;
    std::cout << "SIGMA ORIGINAL ANSWER with More Complex Lookup (breaks Sigma code)" << std::endl;
    std::cout << std::regex_replace(r, markers, lookupUpper("$1", "$2", "$3")) << std::endl;
}

#pragma endregion Sigma original answer

#pragma region Sigma new answer

std::string replace(std::string const& s, std::regex const& re, const bool originalLookup)
{
    std::sregex_iterator rbegin{ s.begin(), s.end(), re };
    std::sregex_iterator rend{};

    if (rbegin == rend)
        return s;

    std::string out;
    for (auto i = rbegin; i != rend; ++i) {
        auto match = *i;
        out += match.prefix();
        if (match.size() == 4) {
            auto spreadsheet = match[1].str();
            auto sheet = match[2].str();
            auto key = match[3].str();
            out += originalLookup ? lookup(spreadsheet, sheet, key) : lookupUpper(spreadsheet, sheet, key);
        }
        if (std::next(i) == rend)
            out += match.suffix();
    }

    return out;
}

void testDefaultsSpreadsheetFieldMarkersReplaceWhatWeNeed()
{
    std::regex markers{ R"(\$\{([\w ._-]+):([\w ._-]+):([\w ._-]+)\})", std::regex::icase };
    const std::string s = "${abc:def:ghi} and ${123:456:789} and ${abc:def:ghi}";
    std::string q = s;
    std::string r = s;

    // The trick here is the special syntax accepted by the "fmt" argument:
    // it will replace $n by the nth capture group
    std::cout << "SIGMA NEW ANSWER with Original Lookup" << std::endl;
    std::cout << replace(q, markers, true) << std::endl;
    std::cout << "SIGMA NEW ANSWER with More Complex Lookup" << std::endl;
    std::cout << replace(r, markers, false) << std::endl;
}

#pragma endregion Sigma new answer

也許沒有那么優雅,但這應該與您的實際代碼兼容。

#include <iostream>
#include <regex>
#include <string>

// lookup function used by all attempts
std::string lookup(std::string spreadsheet, std::string sheet, std::string key) {
    // some placeholder code, the real code would lookup a value from a spreadsheet 
    return "ss=" + spreadsheet + ",sheet=" + sheet + ",key=" + key; 
}

std::string replace(std::string const& s, std::regex const& re)
{
    std::sregex_iterator rbegin {s.begin(), s.end(), re};
    std::sregex_iterator rend {};

    if (rbegin == rend)
        return s;

    std::string out;
    for (auto i = rbegin; i != rend; ++i) {
        auto match = *i;
        out += match.prefix();
        if (match.size() == 4) {
            auto spreadsheet = match[1].str();
            auto sheet = match[2].str();
            auto key = match[3].str();
            out += lookup(spreadsheet, sheet, key);
        }
        if (std::next(i) == rend)
            out += match.suffix();
    }

    return out;
}

int main()
{
    std::regex markers {R"(\$\{([\w ._-]+):([\w ._-]+):([\w ._-]+)\})", std::regex::icase};
    std::string r = "${abc:def:ghi} and ${123:456:789} and ${abc:def:ghi}";
    std::cout << replace(r, markers) << '\n';
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM