M module-utils/Utils.hpp => module-utils/Utils.hpp +48 -5
@@ 89,14 89,57 @@ namespace utils
return ss.str();
}
- static inline void findAndReplaceAll(std::string &data, std::string toSearch, std::string replaceStr)
+ static inline void findAndReplaceAll(std::string &data,
+ const std::vector<std::pair<std::string, std::optional<std::string>>> &values,
+ std::function<std::string(int)> getReplaceString = nullptr)
{
- size_t pos = data.find(toSearch);
- while (pos != std::string::npos) {
- data.replace(pos, toSearch.size(), replaceStr);
- pos = data.find(toSearch, pos + replaceStr.size());
+ int valIdx = 0;
+ for (auto &el : values) {
+ std::string preStr, replaceStr, postStr;
+ const std::string &toSearch = el.first;
+
+ if (toSearch.empty()) {
+ continue;
+ }
+
+ auto begin_pos = data.begin();
+ auto found_pos = data.begin();
+ while (found_pos != data.end()) {
+ begin_pos = data.begin();
+ found_pos = std::search(begin_pos, data.end(), toSearch.begin(), toSearch.end());
+ if (found_pos != data.end()) {
+ preStr = std::string(begin_pos, found_pos);
+ if (replaceStr.empty() && el.second) {
+ replaceStr = *el.second;
+ }
+ else if (replaceStr.empty() && getReplaceString) {
+ replaceStr = getReplaceString(valIdx);
+ }
+ postStr.assign(found_pos + toSearch.size(), data.end());
+ data = preStr + replaceStr + postStr;
+ }
+ }
+ valIdx++;
+ }
+ }
+
+ static inline void findAndReplaceAll(std::string &data,
+ const std::vector<std::string> &values,
+ std::function<std::string(int)> getReplaceString)
+ {
+ std::vector<std::pair<std::string, std::optional<std::string>>> valuePairs;
+ valuePairs.reserve(values.size());
+ for (auto val : values) {
+ valuePairs.emplace_back(std::make_pair(val, std::nullopt));
}
+ findAndReplaceAll(data, valuePairs, getReplaceString);
+ }
+
+ static inline void findAndReplaceAll(std::string &data, const std::string &toSearch, const std::string &replaceStr)
+ {
+ findAndReplaceAll(data, {{toSearch, replaceStr}});
}
+
static inline bool toNumeric(const std::string &text, uint32_t &value)
{
try {
M module-utils/test/test_time_conversion.cpp => module-utils/test/test_time_conversion.cpp +1 -1
@@ 166,7 166,7 @@ bool test_time_from_before(std::ostream &outstream, time_t before, std::string f
strftime(buf, 128, format_expected.c_str(), &todaytime);
- if (!(mytime.str() == buf)) {
+ if (!(mytime.str(format_expected) == buf)) {
std::cerr << "Error: "
<< "\n\t" << mytime.str() << "\n\t"
<< " :vs:"
M module-utils/test/unittest_utils.cpp => module-utils/test/unittest_utils.cpp +73 -0
@@ 75,3 75,76 @@ TEST_CASE("toNumeric tests")
REQUIRE(ret == true);
REQUIRE(value == 2);
}
+
+TEST_CASE("findAndReplaceAll tests")
+{
+ // helper lambda
+ auto compare = [](std::string &data, std::string &expected, bool &retVal) {
+ if (data.compare(expected)) {
+ std::cout << "Expected:" << std::endl
+ << "\t" << expected << std::endl
+ << "But is:" << std::endl
+ << "\t" << data << std::endl;
+ retVal = false;
+ }
+ };
+
+ // test findAndReplaceAll with different data combinations
+ enum
+ {
+ eTestString,
+ eToSearch,
+ eReplace,
+ eExpected
+ };
+ std::vector<std::vector<std::string>> testValues = {
+ // multiple replacements
+ {"%T TT %T TT %t %T", "%T", "test", "test TT test TT %t test"},
+ {"%T TT %T TT %t %T", "%t", "test", "%T TT %T TT test %T"},
+ // capital letter test
+ {"%T TT %T TT %T %T", "%t", "test", "%T TT %T TT %T %T"},
+ // empty test string
+ {"", "%t", "test", ""},
+ // no match
+ {"TEST", "%t", "test", "TEST"},
+ // empty match string
+ {"TEST", "", "test", "TEST"},
+ // empty test string and match string
+ {"", "", "test", ""},
+ // empty test, match and replace
+ {"", "", "", ""},
+ // empty replace string
+ {"%T TT %T TT %T %T", " ", "", "%TTT%TTT%T%T"},
+ };
+
+ std::string testString;
+ bool retVal = true;
+
+ for (auto &testCase : testValues) {
+ testString = testCase[eTestString];
+ utils::findAndReplaceAll(testString, testCase[eToSearch], testCase[eReplace]);
+ compare(testString, testCase[eExpected], retVal);
+ }
+
+ // test findAndReplaceAll with replacement function
+ std::string testFormat, expectedFormat;
+ std::vector<std::string> testValuesFunc = {"A", "B", "C", "D"};
+ // test helper lambdas
+ auto toLower = [](unsigned char c) { return std::tolower(c); };
+ auto replaceFunc = [&](int idx) { return std::string(1, toLower(testValuesFunc[idx][0])); };
+
+ // create test format
+ for (const auto &ch : testValuesFunc) {
+ testFormat += ch;
+ }
+ // create expected result
+ expectedFormat = testFormat;
+ std::transform(expectedFormat.begin(), expectedFormat.end(), expectedFormat.begin(), [toLower](unsigned char c) {
+ return toLower(c);
+ });
+
+ utils::findAndReplaceAll(testFormat, testValuesFunc, replaceFunc);
+ compare(testFormat, expectedFormat, retVal);
+
+ REQUIRE(retVal == true);
+}
M module-utils/time/time_conversion.cpp => module-utils/time/time_conversion.cpp +6 -34
@@ 45,41 45,13 @@ namespace utils
return retval;
}
- void Timestamp::replace_specifiers()
- {
- int replacements_n = 0;
- const int strtof_formatter_size = 2;
- for (auto &el : specifiers_replacement) {
- auto begin_pos = format.begin();
- auto found_pos = format.begin();
- while (found_pos != format.end()) {
- begin_pos = format.begin();
- found_pos = std::search(begin_pos, format.end(), el.begin(), el.end());
- if (found_pos != format.end()) {
- UTF8 begin = std::string(begin_pos, found_pos);
- UTF8 day = get_replacement(Replacements(replacements_n), timeinfo);
- UTF8 next;
- // std::next doesnt care for distance... (doesn't return element.end()) need to check it
- if (std::distance(found_pos, format.end()) <= strtof_formatter_size) {
- next = "";
- }
- else {
- next = std::string(std::next(found_pos, strtof_formatter_size), format.end());
- }
- format = (begin + day + next).c_str();
- }
- }
- ++replacements_n;
- }
- }
-
void Timestamp::set_time(time_t newtime)
{
time = newtime;
timeinfo = *localtime(&time);
}
- void Timestamp::set_time(std::string timestr, const char *format)
+ void Timestamp::set_time(std::string timestr, const char *fmt)
{
std::stringstream stream(timestr);
@@ 96,14 68,14 @@ namespace utils
}
constexpr uint32_t datasize = 128;
- UTF8 Timestamp::str(std::string format)
+ UTF8 Timestamp::str(std::string fmt)
{
- if (format.compare("") != 0) {
- this->format = format;
+ if (fmt.compare("") != 0) {
+ this->format = fmt;
}
UTF8 datetimestr = "";
- replace_specifiers();
-
+ auto replaceFunc = [&](int idx) { return get_replacement(Replacements(idx), timeinfo); };
+ utils::findAndReplaceAll(this->format, specifiers_replacement, replaceFunc);
auto data = std::unique_ptr<char[]>(new char[datasize]);
std::strftime(data.get(), datasize, this->format.c_str(), &timeinfo);
datetimestr = UTF8(data.get());
M module-utils/time/time_conversion.hpp => module-utils/time/time_conversion.hpp +2 -9
@@ 66,13 66,6 @@ namespace utils
return nullptr;
}
- /// replace day mon specifiers (first 2 characters)
- /// cant use std::replace -> due to fact that it doesn't support multiple element replace (or i cant find
- /// it) cant use string::replace -> expcetion out_of_range on size when replacing with bigger (our case)
- /// please be vary when using begin_pos/found_pos (as format in next loops might be in totally different
- /// place)
- void replace_specifiers();
-
public:
Timestamp()
{
@@ 90,7 83,7 @@ namespace utils
/// set Time time_t value held (set timestamp)
void set_time(time_t newtime);
/// set Time from string
- void set_time(std::string time, const char *format);
+ void set_time(std::string time, const char *fmt);
void set_format(std::string format)
{
this->format = format;
@@ 182,7 175,7 @@ namespace utils
void before_n_sec(time_t val);
/// Time have str(std::string ) this one uses presets
- virtual UTF8 str(std::string format = "");
+ virtual UTF8 str(std::string fmt = "");
bool isToday();
bool isYesterday();
};