Updated string split method to accept limitParts and ignoreEmpty options.

This commit is contained in:
Patrick 2024-08-18 17:24:06 +02:00
parent d508ccfe2b
commit 03c899f17e

View File

@ -5,7 +5,7 @@
#define MIJIN_UTIL_STRING_HPP_INCLUDED 1
#include <iterator>
#include <ranges>
#include <limits>
#include <sstream>
#include <string>
#include <string_view>
@ -28,6 +28,12 @@ namespace mijin
// public types
//
struct SplitOptions
{
std::size_t limitParts = std::numeric_limits<std::size_t>::max();
bool ignoreEmpty = true;
};
//
// public functions
//
@ -56,11 +62,74 @@ namespace detail
{
template<typename TChar, typename TTraits>
std::vector<std::basic_string_view<TChar, TTraits>> splitImpl(std::basic_string_view<TChar, TTraits> stringView,
std::basic_string_view<TChar, TTraits> seperator)
std::basic_string_view<TChar, TTraits> separator,
const SplitOptions& options)
{
return std::views::split(stringView, seperator)
| std::views::transform([](auto val) { return std::string_view(val); })
| std::ranges::to<std::vector>();
using sv_t = std::basic_string_view<TChar, TTraits>;
MIJIN_ASSERT(options.limitParts > 0, "Cannot split to zero parts.");
MIJIN_ASSERT(!separator.empty(), "Separator cannot be empty.");
if (separator.empty())
{
return {};
}
std::vector<sv_t> result;
if (options.limitParts <= 1)
{
result.push_back(stringView);
return result;
}
auto start = stringView.begin();
auto pos = start;
const auto end = stringView.end();
auto seperatorFound = [&]()
{
return pos <= (end - separator.size()) && sv_t(pos, pos + separator.size()) == separator;
};
while (pos != end)
{
if (seperatorFound())
{
if (!options.ignoreEmpty || pos != start)
{
result.emplace_back(start, pos);
}
start = pos = (pos + separator.size());
if (result.size() == options.limitParts - 1)
{
if (options.ignoreEmpty)
{
while (seperatorFound())
{
pos += separator.size();
}
}
result.emplace_back(pos, end);
return result;
}
if (!options.ignoreEmpty && pos == end)
{
// skipped a separator at the very end, add an empty entry
result.emplace_back("");
return result;
}
}
else
{
++pos;
}
}
if (start != end)
{
result.emplace_back(start, end);
}
return result;
}
template<typename TChar, typename TTraitsA, typename TTraitsB>
@ -87,9 +156,10 @@ static const TChar SPACE = TChar(' ');
}
template<typename TLeft, typename TRight>
[[nodiscard]] auto split(TLeft&& left, TRight&& right)
[[nodiscard]] auto split(TLeft&& stringView, TRight&& separator, const SplitOptions& options = {})
{
return detail::splitImpl(std::basic_string_view(std::forward<TLeft>(left)), std::basic_string_view(std::forward<TRight>(right)));
return detail::splitImpl(std::basic_string_view(std::forward<TLeft>(stringView)),
std::basic_string_view(std::forward<TRight>(separator)), options);
}
template<typename TChar, typename TTraits>