General Utility Library for C++17 25.4.1
join_split.h
Go to the documentation of this file.
1
23#ifndef GUL17_JOIN_SPLIT_H_
24#define GUL17_JOIN_SPLIT_H_
25
26#include <iterator>
27#include <regex>
28#include <string_view>
29#include <string>
30#include <type_traits>
31#include <vector>
32
33#include "gul17/internal.h"
34#include "gul17/string_util.h"
35
36namespace gul17 {
37
121template <typename StringContainer = std::vector<std::string>,
122 typename ContainerInsertFct = void (*)(StringContainer&, std::string_view)>
123inline StringContainer
124split(std::string_view text, std::string_view delimiter,
125 ContainerInsertFct insert_fct = detail::emplace_back<StringContainer>)
126{
127 using StringType = typename StringContainer::value_type;
128 using SizeType = typename StringType::size_type;
129
130 auto result = StringContainer{ };
131 auto search_start = SizeType{ 0 };
133
134 for (;;) {
135 const auto hit = text.find(delimiter.data(), search_start, delimiter.size());
136 if (hit == StringType::npos)
137 break;
138 const auto hit_len = hit - push_start;
140 search_start += std::max(delimiter.size() + hit_len, SizeType{ 1 });
141 push_start += delimiter.size() + hit_len;
142 }
144 return result;
145}
146
172template <typename StringContainer = std::vector<std::string>,
173 typename ContainerInsertFct = void (*)(StringContainer&, std::string_view)>
174inline StringContainer
175split(std::string_view text, const std::regex& delimiter,
176 ContainerInsertFct insert_fct = detail::emplace_back<StringContainer>)
177{
178 auto const end = std::cregex_iterator{ };
179 auto result = StringContainer{ };
180
181 auto parts = std::cregex_iterator(text.data(), text.data() + text.size(), delimiter);
182 if (parts == end)
183 {
185 }
186 else
187 {
188 auto previous = std::cregex_iterator{ };
189 for (; parts != end; ++parts) {
190 if (parts == previous and not parts->length())
191 break;
192 auto const& match = parts->prefix();
193 insert_fct(result, std::string_view(match.first, match.length()));
194 previous = parts;
195 }
196
197 auto const& match = previous->suffix();
198 insert_fct(result, std::string_view(match.first, match.length()));
199 }
200
201 return result;
202}
203
226template <typename StringContainer = std::vector<std::string_view>,
227 typename ContainerInsertFct = void (*)(StringContainer&, std::string_view)>
228inline StringContainer
229split_sv(std::string_view text, std::string_view delimiter,
230 ContainerInsertFct insert_fct = detail::emplace_back<StringContainer>)
231{
233}
234
235namespace detail {
236
237// Type trait to check if a type has a member function size()
238template <typename, typename = void>
239struct HasSize : std::false_type
240{};
241
242template <typename T>
243struct HasSize<T, std::void_t<decltype(std::declval<const T&>().size())>> : std::true_type
244{};
245
246} // namespace detail
247
282template <typename Iterator>
283inline std::string
284join(Iterator begin, Iterator end, std::string_view glue)
285{
286 using ElementType = decltype(*begin);
287 std::string result;
288
289 if (begin == end)
290 return result; // Return an empty string
291
292 if constexpr (detail::HasSize<ElementType>::value)
293 {
294 std::size_t num_strings = 0;
295 std::size_t len = 0;
296
297 for (auto it = begin; it != end; ++it)
298 {
299 ++num_strings;
300 len += it->size();
301 }
302 len += (num_strings - 1) * glue.size();
303
304 result.reserve(len);
305 }
306
307 result += *begin;
308
309 // Iterate over all but the first string
310 for (auto it = std::next(begin); it != end; ++it)
311 {
312 result.append(glue.data(), glue.size());
313 result += *it;
314 }
315
316 return result;
317}
318
358template <typename StringContainer>
359inline std::string
360join(const StringContainer& parts, std::string_view glue)
361{
362 return join(parts.begin(), parts.end(), glue);
363}
364
397template <typename Iterator, typename ConversionFct>
398inline std::string
399join(Iterator begin, Iterator end, std::string_view glue, ConversionFct to_string,
400 std::size_t prealloc = 0)
401{
402 static_assert(std::is_invocable_v<ConversionFct, decltype(*begin)>,
403 "ConversionFct does not accept the element type of the range");
404
405 std::string result;
406
407 if (begin == end)
408 return result; // Return an empty string
409
410 result.reserve(prealloc);
411 result += to_string(*begin);
412
413 // Iterate over all but the first element of the range
414 for (auto it = std::next(begin); it != end; ++it)
415 {
416 result += glue;
417 result += to_string(*it);
418 }
419
420 return result;
421}
422
453template <typename Container, typename ConversionFct>
454inline std::string
456 std::size_t prealloc = 0)
457{
458 return join(container.cbegin(), container.cend(), glue, to_string, prealloc);
459}
460
462
463} // namespace gul17
464
465#endif
466
467/* 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:121
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:229
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:284
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:124
Definition of macros used internally by GUL.
Namespace gul17 contains all functions and classes of the General Utility Library.
Definition doxygen.h:26
Declaration of string utility functions.