我對所有事物都很陌生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
uj5u.com熱心網友回復:
也許沒有那么優雅,但這應該與您的實際代碼兼容。
#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';
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/496157.html
