![](/img/trans.png)
[英]Regex that matches a string that ends with the same sequence as it begins
[英]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.