diff --git a/base/base_tests/string_utils_test.cpp b/base/base_tests/string_utils_test.cpp index 7e5eec9031..7511f17713 100644 --- a/base/base_tests/string_utils_test.cpp +++ b/base/base_tests/string_utils_test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -841,3 +842,45 @@ UNIT_TEST(UniString_Replace) TEST_EQUAL(testString, ToUtf8(uniStr), ()); } } + +UNIT_TEST(Strings_JoinAny) +{ + { + std::vector testSequence{1, 2, 3}; + std::string expected{"1,2,3"}; + TEST_EQUAL(expected, strings::JoinAny(testSequence), ()); + } + { + std::list testSequence{"1", "2", "3"}; + std::string expected{"1,2,3"}; + TEST_EQUAL(expected, strings::JoinAny(testSequence), ()); + } + { + std::vector testSequence{'1', '2', '3'}; + std::string expected{"1,2,3"}; + TEST_EQUAL(expected, strings::JoinAny(testSequence), ()); + } + { + std::list testSequence{"1", "2", "3"}; + std::string expected{"1xyz2xyz3"}; + TEST_EQUAL(expected, strings::JoinAny(testSequence, "xyz"), ()); + } + { + std::vector testSequence{"name:X", "name:Y", "name:Z"}; + std::string expected{"X; Y; Z"}; + TEST_EQUAL(expected, + strings::JoinAny(testSequence, "; ", + [](auto const & line) { + auto const pos = line.find(":"); + return line.substr(pos + 1); + }), + ()); + } + { + std::map testSequence{{1, "maps"}, {2, "."}, {3, "me"}}; + std::string expected{"maps.me"}; + TEST_EQUAL(expected, + strings::JoinAny(testSequence, "", + [](auto const & item) { return item.second; }), ()); + } +} diff --git a/base/string_utils.hpp b/base/string_utils.hpp index 43cc707fee..353ecd91f4 100644 --- a/base/string_utils.hpp +++ b/base/string_utils.hpp @@ -568,6 +568,35 @@ typename Container::value_type JoinStrings(Container const & container, Delimite return JoinStrings(begin(container), end(container), delimiter); } +template +std::string JoinAny(Iterator first, Iterator last, Delimiter const & delimiter, + Converter const & converter) +{ + if (first == last) + return {}; + + std::string result(converter(*first)); + ++first; + + for (; first != last; ++first) + { + result += delimiter; + result += converter(*first); + } + return result; +} + +template +std::string JoinAny(Container const & container, + Delimiter const & delimiter = ',', + std::function< + std::string (typename Container::value_type const & v)> const & converter = + [](typename Container::value_type const & item) + { return to_string(item); }) +{ + return JoinAny(std::cbegin(container), std::cend(container), delimiter, converter); +} + template void ForEachMatched(std::string const & s, std::regex const & regex, Fn && fn) {