General Utility Library for C++17 26.5.0
join_split.h
Go to the documentation of this file.
1
26#ifndef GUL17_JOIN_SPLIT_H_
27#define GUL17_JOIN_SPLIT_H_
28
29#include <iterator>
30#include <regex>
31#include <string_view>
32#include <string>
33#include <type_traits>
34#include <vector>
35
36#include "gul17/internal.h"
37#include "gul17/string_util.h"
38
39namespace gul17 {
40
124template <typename StringContainer = std::vector<std::string>,
125 typename ContainerInsertFct = void (*)(StringContainer&, std::string_view)>
126inline StringContainer
127split(std::string_view text, std::string_view delimiter,
128 ContainerInsertFct insert_fct = detail::emplace_back<StringContainer>)
129{
130 using StringType = typename StringContainer::value_type;
131 using SizeType = typename StringType::size_type;
132
133 auto result = StringContainer{ };
134 auto search_start = SizeType{ 0 };
136
137 for (;;) {
138 const auto hit = text.find(delimiter.data(), search_start, delimiter.size());
139 if (hit == StringType::npos)
140 break;
141 const auto hit_len = hit - push_start;
143 search_start += std::max(delimiter.size() + hit_len, SizeType{ 1 });
144 push_start += delimiter.size() + hit_len;
145 }
147 return result;
148}
149
175template <typename StringContainer = std::vector<std::string>,
176 typename ContainerInsertFct = void (*)(StringContainer&, std::string_view)>
177inline StringContainer
178split(std::string_view text, const std::regex& delimiter,
179 ContainerInsertFct insert_fct = detail::emplace_back<StringContainer>)
180{
181 auto const end = std::cregex_iterator{ };
182 auto result = StringContainer{ };
183
184 auto parts = std::cregex_iterator(text.data(), text.data() + text.size(), delimiter);
185 if (parts == end)
186 {
188 }
189 else
190 {
191 auto previous = std::cregex_iterator{ };
192 for (; parts != end; ++parts) {
193 if (parts == previous and not parts->length())
194 break;
195 auto const& match = parts->prefix();
196 insert_fct(result, std::string_view(match.first, static_cast<std::size_t>(match.length())));
197 previous = parts;
198 }
199
200 auto const& match = previous->suffix();
201 insert_fct(result, std::string_view(match.first, static_cast<std::size_t>(match.length())));
202 }
203
204 return result;
205}
206
229template <typename StringContainer = std::vector<std::string_view>,
230 typename ContainerInsertFct = void (*)(StringContainer&, std::string_view)>
231inline StringContainer
232split_sv(std::string_view text, std::string_view delimiter,
233 ContainerInsertFct insert_fct = detail::emplace_back<StringContainer>)
234{
236}
237
238namespace detail {
239
240// Type trait to check if a type has a member function size()
241template <typename, typename = void>
242struct HasSize : std::false_type
243{};
244
245template <typename T>
246struct HasSize<T, std::void_t<decltype(std::declval<const T&>().size())>> : std::true_type
247{};
248
249} // namespace detail
250
285template <typename Iterator>
286inline std::string
287join(Iterator begin, Iterator end, std::string_view glue)
288{
289 using ElementType = decltype(*begin);
290 std::string result;
291
292 if (begin == end)
293 return result; // Return an empty string
294
295 if constexpr (detail::HasSize<ElementType>::value)
296 {
297 std::size_t num_strings = 0;
298 std::size_t len = 0;
299
300 for (auto it = begin; it != end; ++it)
301 {
302 ++num_strings;
303 len += it->size();
304 }
305 len += (num_strings - 1) * glue.size();
306
307 result.reserve(len);
308 }
309
310 result += *begin;
311
312 // Iterate over all but the first string
313 for (auto it = std::next(begin); it != end; ++it)
314 {
315 result.append(glue.data(), glue.size());
316 result += *it;
317 }
318
319 return result;
320}
321
361template <typename StringContainer>
362inline std::string
363join(const StringContainer& parts, std::string_view glue)
364{
365 return join(parts.begin(), parts.end(), glue);
366}
367
400template <typename Iterator, typename ConversionFct>
401inline std::string
402join(Iterator begin, Iterator end, std::string_view glue, ConversionFct to_string,
403 std::size_t prealloc = 0)
404{
405 static_assert(std::is_invocable_v<ConversionFct, decltype(*begin)>,
406 "ConversionFct does not accept the element type of the range");
407
408 std::string result;
409
410 if (begin == end)
411 return result; // Return an empty string
412
413 result.reserve(prealloc);
414 result += to_string(*begin);
415
416 // Iterate over all but the first element of the range
417 for (auto it = std::next(begin); it != end; ++it)
418 {
419 result += glue;
420 result += to_string(*it);
421 }
422
423 return result;
424}
425
456template <typename Container, typename ConversionFct>
457inline std::string
459 std::size_t prealloc = 0)
460{
461 return join(container.cbegin(), container.cend(), glue, to_string, prealloc);
462}
463
465
466} // namespace gul17
467
468#endif
469
470/* vim:set noexpandtab softtabstop=4 tabstop=4 shiftwidth=4 textwidth=90 cindent: */
auto constexpr bit_set(unsigned bit) noexcept -> ReturnT
Set a bit in an integral type.
Definition bit_manip.h:124
StringContainer split_sv(std::string_view text, std::string_view delimiter, ContainerInsertFct insert_fct=detail::emplace_back< StringContainer >)
Separate a string at all occurrences of a delimiter, returning the strings between the delimiters in ...
Definition join_split.h:232
std::string join(Iterator begin, Iterator end, std::string_view glue)
Concatenate all strings (or string-like elements) in a range, placing a delimiter between them.
Definition join_split.h:287
StringContainer split(std::string_view text, std::string_view delimiter, ContainerInsertFct insert_fct=detail::emplace_back< StringContainer >)
Separate a string at all occurrences of a delimiter, returning the strings between the delimiters in ...
Definition join_split.h:127
Definition of macros used internally by GUL.
Namespace gul17 contains all functions and classes of the General Utility Library.
Definition doxygen.h:29
Declaration of string utility functions.