Updated string split method to accept limitParts and ignoreEmpty options.
This commit is contained in:
parent
d508ccfe2b
commit
03c899f17e
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user