ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
substring.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of module \alib_strings of the \aliblong.
4///
5/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8#ifndef HPP_ALIB_STRINGS_SUBSTRING
9#define HPP_ALIB_STRINGS_SUBSTRING 1
10#pragma once
13
14namespace alib { namespace strings {
15
16//==================================================================================================
17/// This class specializes parent class \alib{strings;TString;String} to allow reduction of
18/// the length of the represented string by cutting characters from the front or the end.
19/// Such reduction does not affect the character array represented, but only its representation
20/// by instances of this type.
21///
22/// In other words, the difference to base class \alib{strings;TString;String} is, that this type
23/// allows increasing the pointer to the character array's start and to decrease its stored length.
24/// In all other respects, this class has the same lightweight nature and performance as its base.
25/// Furthermore, the flexible TMP mechanics for seamless construction is exposed from the base
26/// class and likewise available.
27///
28/// Like base class \alib{strings;TString;String}, the class cannot, and therefore does not,
29/// verify that the underlying buffer is (still) properly allocated and contains valid data.
30/// It is up to the user of this class to make sure the buffer stays intact until any referencing
31/// object of this type is disposed.
32///
33/// @tparam TChar The \ref alib_characters_chars "character type" of this string-type.
34/// Alias names for specializations along the different character types
35/// are provided in namespace #alib with type definitions
36/// \alib{Substring},
37/// \alib{NSubstring},
38/// \alib{WSubstring},
39/// \alib{XSubstring},
40/// \alib{ComplementSubstring}, and
41/// \alib{StrangeSubstring}.
42//==================================================================================================
43template<typename TChar>
44class TSubstring : public TString<TChar>
45{
46 protected:
47 /// The base string-type.
49
50 public:
51 #if !DOXYGEN
52 // Import parent constructors
53 // Due to a doxygen bug in 1.8.14, we must not tell doxygen that we import overloaded methods.
54 using base::TString;
55 #endif
56
57 //==============================================================================================
58 /// Default constructor creating a \ref alib_strings_details_nulled \e "nulled" substring.
59 //==============================================================================================
61 : base()
62 {}
63
64 //==============================================================================================
65 /// Constructor using a string reference.
66 /// @param src The source string.
67 //==============================================================================================
69 : base(src)
70 {}
71
72 //==============================================================================================
73 /// Sets this object to zero length.
74 /// @return \c *this to allow concatenated calls.
75 //==============================================================================================
77 {
78 base::length= 0;
79 return *this;
80 }
81
82 //==============================================================================================
83 /// Moves the start to the first character not found in given character set \p{whiteSpaces}.
84 ///
85 /// @param whiteSpaces The characters used for trimming.
86 /// Defaults to \ref alib::DEFAULT_WHITESPACES
87 /// @return \c *this to allow concatenated calls.
88 //==============================================================================================
91 {
92 if ( base::length > 0 )
93 {
96 whiteSpaces.Buffer(),
97 whiteSpaces.Length() );
98 if( idx < 0 )
99 idx= base::length;
101 base::buffer+= idx;
102 base::length-= idx;
104 }
105 return *this;
106 }
107
108 //==============================================================================================
109 /// Moves the start to the first character not found in given character set \p{whiteSpaces}.
110 ///
111 /// @param whiteSpaces The characters used for trimming.
112 /// Defaults to \ref alib::DEFAULT_WHITESPACES
113 /// @return \c *this to allow concatenated calls.
114 //==============================================================================================
115 TSubstring& TrimEnd( const TCString<TChar>& whiteSpaces
117 {
118 if ( base::length > 0 )
119 {
121 base::length - 1,
122 whiteSpaces.Buffer(),
123 whiteSpaces.Length() ) + 1;
124 }
125 return *this;
126 }
127
128 //==============================================================================================
129 /// Invokes #TrimStart and #TrimEnd .
130 ///
131 /// @param whiteSpaces The characters used for trimming.
132 /// Defaults to \ref alib::DEFAULT_WHITESPACES
133 /// @return \c *this to allow concatenated calls.
134 //==============================================================================================
135 TSubstring& Trim( const TCString<TChar>& whiteSpaces
137 {
138 return TrimEnd ( whiteSpaces )
139 .TrimStart( whiteSpaces );
140 }
141
142 //==============================================================================================
143 /// Retrieve and remove the first character from the substring.
144 ///
145 /// @tparam TTrimBeforeConsume Determines if the string should be (left-) trimmed before the
146 /// consume operation. Defaults to \b Whitespaces::Keep.
147 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
148 /// If \c <false> is added to the method name, no parameter check is
149 /// performed.
150 ///
151 /// @return The character at the start of the represented region.
152 /// If this \b %Substring is empty or \e nulled, '\0' is returned.
153 //==============================================================================================
154 template < typename TCheck = CHK,
155 lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep >
157 {
158 if constexpr ( TCheck::value )
159 {
160 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
161 TrimStart();
162 if( base::IsEmpty() )
163 return '\0';
164 }
165 else
166 {
167 ALIB_ASSERT_ERROR( !base::IsEmpty(), "STRINGS",
168 "Non checking but called on empty string" )
169 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
170 TrimStart();
171 }
172
173 --base::length;
175 return *base::buffer++;
177 }
178
179 //==============================================================================================
180 /// Checks if this object starts with the given character \p{consumable}. If it does, this
181 /// character is cut from this object.
182 ///
183 /// @tparam TSensitivity The sensitivity of the comparison.
184 /// Defaults to \b Case::Sensitive.
185 /// @tparam TTrimBeforeConsume Determines if the string should be (left-) trimmed before the
186 /// consume operation. Defaults to \b Whitespaces::Keep.
187 /// @param consumable The consumable character.
188 /// @return \c true, if this object was starting with \p{consumable} and consequently the
189 /// string was cut by one, \c false otherwise.
190 //==============================================================================================
191 template< lang::Case TSensitivity= lang::Case::Sensitive,
192 lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep>
193 bool ConsumeChar( TChar consumable )
194
195 {
196 if ( TTrimBeforeConsume == lang::Whitespaces::Trim )
197 TrimStart();
198
199 if ( ( TSensitivity == lang::Case::Sensitive && base::CharAtStart() != consumable )
201 != characters::ToUpper(consumable) ) )
202 return false;
203
205 ++base::buffer;
206 --base::length;
208 return true;
209 }
210
211 //==============================================================================================
212 /// Checks if this object ends with the given character \p{consumable}. If it does, this
213 /// character is cut from the end of object.
214 ///
215 /// @tparam TSensitivity The sensitivity of the comparison.
216 /// Defaults to \b Case::Sensitive.
217 /// @tparam TTrimBeforeConsume Determines if the string should be (left-) trimmed before the
218 /// consume operation. Defaults to \b Whitespaces::Keep.
219 /// @param consumable The consumable character.
220 /// @return \c true, if this object was starting with \p{consumable} and consequently the
221 /// string was cut by one.
222 //==============================================================================================
223 template< lang::Case TSensitivity= lang::Case::Sensitive,
224 lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep>
225 bool ConsumeCharFromEnd( TChar consumable )
226 {
227 if ( TTrimBeforeConsume == lang::Whitespaces::Trim )
228 TrimEnd();
229
230 if ( ( TSensitivity == lang::Case::Sensitive && base::CharAtEnd() != consumable )
232 != characters::ToUpper(consumable) ) )
233 return false;
234 --base::length;
235 return true;
236 }
237
238 //==============================================================================================
239 /// Retrieve and remove the last character in the substring.
240 ///
241 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
242 /// If \c <false> is added to the method name, no check whether this
243 /// string is empty is performed.
244 ///
245 /// @tparam TTrimBeforeConsume Determines if the string should be (right-) trimmed before the
246 /// consume operation. Defaults to \b Whitespaces::Keep.
247 /// @return The character at the start of the represented region.
248 /// If this \b %Substring is empty or \e nulled, '\0' is returned.
249 //==============================================================================================
250 template <typename TCheck= CHK,
251 lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep >
253 {
254 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
255 TrimEnd();
256
258 if constexpr ( TCheck::value )
259 {
260 if( base::IsEmpty() )
261 return '\0';
262 }
263 else
264 {
265 ALIB_ASSERT_ERROR( !base::IsEmpty(), "STRINGS",
266 "Non checking but called on empty string" )
267 }
268 return *(base::buffer + --base::length );
270 }
271
272 //==============================================================================================
273 /// Cuts the given number of characters from the beginning of the Substring and optionally
274 /// places the portion that was cut in parameter \p{target} (if provided).<br>
275 ///
276 /// If parameter \p{regionLength} is negative, nothing is cut and optional argument
277 /// \p{target} is set empty. If \p{regionLength} is equal or greater than this
278 /// object's length, all contents is 'moved' to \p{target}.
279 ///
280 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
281 /// If \c <false>, parameter \p{regionLength} has to be in the range of
282 /// this object's size.
283 ///
284 /// @param regionLength The length of the region at the start to delete.
285 /// @param target An optional target \b %Substring that receives the portion that
286 /// is cut from this object. Defaults to nullptr.
287 ///
288 /// @return The new length of the substring.
289 //==============================================================================================
290 template <typename TCheck= CHK>
291 integer ConsumeChars( integer regionLength, TSubstring* target= nullptr )
292 {
293 if constexpr ( TCheck::value )
294 {
295 if ( regionLength < 0 )
296 {
297 if ( target != nullptr )
298 target->Clear();
299 return base::length;
300 }
301 if ( regionLength > base::length )
302 regionLength= base::length;
303 }
304 else
305 {
306 ALIB_ASSERT_ERROR( regionLength >=0 && regionLength <= base::length,
307 "STRINGS", "Non checking but regionLength out of bounds" )
308 }
309
310 if ( target != nullptr )
311 *target= this->base::template Substring<NC>( 0, regionLength );
312
314 base::buffer+= regionLength;
315 base::length-= regionLength;
317 return base::length;
318 }
319
320 //==============================================================================================
321 /// Cuts the given number of characters from the end of the \b %Substring and optionally
322 /// places the portion that was cut in parameter \p{target} (if provided).<br>
323 /// Parameter \p{regionLength} is checked to be between 0 and length. If negative, nothing
324 /// is cut and \p{target} is set empty. If \p{regionLength} is greater than this
325 /// object's length, all contents is 'moved' to \p{target}.
326 ///
327 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
328 /// If \c <false> is added to the method name, no parameter check is
329 /// performed.
330 ///
331 /// @param regionLength The length of the region at the start to delete.
332 /// @param target An optional target \b %Substring that receives the portion that
333 /// is cut from this object. Defaults to nullptr.
334 ///
335 /// @return The new length of the substring.
336 //==============================================================================================
337 template <typename TCheck= CHK>
338 integer ConsumeCharsFromEnd( integer regionLength, TSubstring* target= nullptr )
339 {
340 if constexpr ( TCheck::value )
341 {
342 if ( regionLength < 0 )
343 {
344 if ( target != nullptr )
345 target->Clear();
346 return base::length;
347 }
348 if ( regionLength > base::length )
349 regionLength= base::length;
350 }
351 else
352 {
353 ALIB_ASSERT_ERROR( regionLength >=0 && regionLength <= base::length,
354 "STRINGS", "Non checking but regionLength out of bounds" )
355 }
356
357 if ( target != nullptr )
358 *target= this->base::template Substring<NC>( base::length - regionLength, regionLength );
359
360 base::length-= regionLength;
361 return base::length;
362 }
363
364 //==============================================================================================
365 /// Cuts the given number of characters from the beginning of the Substring and optionally
366 /// places the portion that was cut in parameter \p{target}.<br>
367 /// Parameter \p{regionLength} is checked to be between 0 and length. If negative, nothing
368 /// is cut and \p{target} is set empty, respectively left untouched depending on
369 /// \p{TTargetData}.
370 ///
371 /// If \p{regionLength} is greater than this object's length, all contents is 'moved'
372 /// to \p{target}.
373 ///
374 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
375 /// If \c <false> is added to the method name, no parameter check
376 /// is performed.
377 /// @tparam TTargetData If \c CurrentData::Keep, \b %AString \p{target} is not cleared
378 /// before the result is written. Defaults to \c CurrentData::Clear.
379 /// @tparam TAllocator The allocation type of the \p{target} string, as prototyped with
380 /// \alib{lang;Allocator}. Deduced by the compiler.
381 /// @param regionLength The length of the region at the start to delete.
382 /// @param target A target \b %AString that receives the portion that
383 /// is cut from this object.
384 /// @param separatorWidth This width is added to what is cut from this string, while
385 /// \p{target} still receives the portion defined by \p{regionLength}.
386 /// Defaults to 0.
387 ///
388 /// @return The new length of the substring.
389 //==============================================================================================
390 template <typename TCheck = CHK,
392 typename TAllocator >
395 integer separatorWidth =0 )
396 {
397 if constexpr ( TTargetData == lang::CurrentData::Clear )
398 target.Reset();
399
400 if constexpr ( TCheck::value )
401 {
402 if ( separatorWidth < 0 )
403 separatorWidth= 0;
404
405 if ( regionLength < 0 )
406 return base::length;
407
408 if ( regionLength > base::length - separatorWidth )
409 {
410 regionLength= base::length - separatorWidth;
411 if ( regionLength < 0 )
412 return base::length;
413 }
414
415 }
416 else
417 {
418 ALIB_ASSERT_ERROR( separatorWidth >= 0,
419 "STRINGS", "Non checking but separator width negative" )
420 ALIB_ASSERT_ERROR( regionLength >= 0
421 && regionLength + separatorWidth <= base::length,
422 "STRINGS", "Non checking but regionLength out of bounds" )
423 }
424
425 target.template _<NC>( *this, 0, regionLength );
426
427 regionLength+= separatorWidth;
429 base::buffer+= regionLength ;
430 base::length-= regionLength;
432 return base::length;
433 }
434
435 //==============================================================================================
436 /// Cuts the given number of characters from the beginning of the Substring and optionally
437 /// places the portion that was cut in parameter \p{target}.<br>
438 /// Parameter \p{regionLength} is checked to be between 0 and length. If negative, nothing
439 /// is cut and \p{target} is set empty, respectively left untouched depending on
440 /// \p{TTargetData}.
441 ///
442 /// If \p{regionLength} is greater than this object's length, all contents is 'moved'
443 /// to \p{target}.
444 ///
445 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
446 /// If \c <false> is added to the method name, no parameter check is
447 /// performed.
448 ///
449 /// @param regionLength The length of the region at the start to delete.
450 /// @param target A target \b %String that receives the portion that
451 /// is cut from this object.
452 /// @param separatorWidth This width is added to what is cut from this string, while
453 /// \p{target} still receives the portion defined by \p{regionLength}.
454 /// Defaults to 0.
455 ///
456 /// @return The new length of the substring.
457 //==============================================================================================
458 template <typename TCheck = CHK>
460 TString<TChar>& target,
461 integer separatorWidth =0 )
462 {
463 if constexpr ( TCheck::value )
464 {
465 if ( separatorWidth < 0 )
466 separatorWidth= 0;
467
468 if ( regionLength < 0 )
469 return base::length;
470
471 if ( regionLength > base::length - separatorWidth )
472 {
473 regionLength= base::length - separatorWidth;
474 if ( regionLength < 0 )
475 return base::length;
476 }
477 }
478 else
479 {
480 ALIB_ASSERT_ERROR( separatorWidth >= 0,
481 "STRINGS", "Non checking but separator width negative" )
482 ALIB_ASSERT_ERROR( regionLength >= 0
483 && regionLength + separatorWidth <= base::length,
484 "STRINGS", "Non checking but regionLength out of bounds" )
485 }
486
487 target= String( base::buffer, regionLength );
488
489 regionLength+= separatorWidth;
491 base::buffer+= regionLength ;
492 base::length-= regionLength;
494 return base::length;
495 }
496
497 //==============================================================================================
498 /// Cuts the given number of characters from the end of the substring and
499 /// places the portion that was cut in parameter \p{target}.<br>
500 /// Parameter \p{regionLength} is checked to be between 0 and length. If negative, nothing
501 /// is cut and \p{target} is set empty, respectively left untouched depending on \p
502 /// If \p{regionLength} is greater than this object's length, all contents is 'moved'
503 /// to \p{target}.
504 ///
505 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
506 /// If \c <false> is added to the method name, no parameter check is
507 /// performed.
508 /// @tparam TTargetData If \c CurrentData::Keep, the parameter \p{target} is not cleared
509 /// before the result is written. Defaults to \c CurrentData::Clear.
510 ///
511 /// @param regionLength The length of the region at the start to delete.
512 /// @param target A target \b %AString that receives the portion that
513 /// is cut from this object.
514 /// @param separatorWidth This width is added to what is cut from this string, while
515 /// \p{target} still receives the portion defined by \p{regionLength}.
516 /// Defaults to 0.
517 ///
518 /// @return The new length of the substring.
519 //==============================================================================================
520 template <typename TCheck = CHK,
523 AString& target,
524 integer separatorWidth =0 )
525 {
526 if constexpr ( TTargetData == lang::CurrentData::Clear )
527 target.Reset();
528
529 if constexpr ( TCheck::value )
530 {
531 if ( separatorWidth < 0 ) separatorWidth= 0;
532 if ( regionLength < 0 ) return base::length;
533 if ( regionLength > base::length - separatorWidth ) regionLength= base::length - separatorWidth;
534 if ( regionLength < 0 ) return base::length;
535 }
536 else
537 {
538 ALIB_ASSERT_ERROR( separatorWidth >=0 ,
539 "STRINGS", "Non checking but separator width negative" )
540 ALIB_ASSERT_ERROR( regionLength >=0 && regionLength + separatorWidth <= base::length,
541 "STRINGS", "Non checking but regionLength out of bounds" )
542 }
543
544 target._<NC>( *this, base::length - regionLength, regionLength );
545
546 base::length-= regionLength + separatorWidth;
547 return base::length;
548 }
549
550 //==============================================================================================
551 /// Searches \p{separator} and cuts the beginning of this string.
552 /// What was consumed is returned.
553 ///
554 /// If the separator is \b not found, all of this string is consumed and returned.
555 ///
556 /// @param separator The separator to search. Defaults to <c>','</c>.
557 /// @param includeSeparator Determines if the separator should be consumed as well.
558 /// defaults to \alib{lang;Inclusion;Include}
559 ///
560 /// @return The token consumed.
561 //==============================================================================================
562 TString<TChar> ConsumeToken( TChar separator= ',',
563 lang::Inclusion includeSeparator = lang::Inclusion::Include )
564 {
566 "STRINGS", "ConsumeToken on nulled Substring" )
567
568 integer separatorPos= base::IndexOfOrLength( separator );
569 base result = base( base::buffer, separatorPos );
570
572 base::buffer+= separatorPos;
573 base::length-= separatorPos;
574 if( includeSeparator == lang::Inclusion::Include
575 && base::length > 0 )
576 {
577 ++base::buffer;
578 --base::length;
579 }
581 return result;
582 }
583
584 //==============================================================================================
585 /// Checks if this object starts with the given string \p{consumable}. If it does, this
586 /// string is cut from this object.
587 ///
588 /// @tparam TSensitivity The sensitivity of the comparison.
589 /// Defaults to \b Case::Sensitive.
590 /// @tparam TTrimBeforeConsume Determines if the string should be (left-) trimmed before the
591 /// consume operation. Defaults to \b Whitespaces::Keep.
592 /// @param consumable The consumable string.
593 /// @return \c true, if this object was starting with \p{consumable} and consequently the
594 /// string was cut.
595 //==============================================================================================
596 template< lang::Case TSensitivity= lang::Case::Sensitive,
597 lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep >
598 bool ConsumeString( const TString<TChar>& consumable )
599 {
600 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
601 TrimStart();
602
603 if ( !base::template StartsWith<CHK,TSensitivity>( consumable ) )
604 return false;
605
607 base::buffer+= consumable.Length();
608 base::length-= consumable.Length();
610 return true;
611 }
612
613 //==============================================================================================
614 /// Checks if this object ends with the given string \p{consumable}. If it does, this
615 /// string is cut from the end of object.
616 ///
617 /// @tparam TSensitivity The sensitivity of the comparison.
618 /// Defaults to \b Case::Sensitive.
619 /// @tparam TTrimBeforeConsume Determines if the string should be (left-) trimmed before the
620 /// consume operation. Defaults to \b Whitespaces::Keep.
621 /// @param consumable The consumable string
622 /// @return \c true, if this object was starting with \p{consumable} and consequently the
623 /// string was cut.
624 //==============================================================================================
625 template< lang::Case TSensitivity= lang::Case::Sensitive,
626 lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep >
627 bool ConsumeStringFromEnd( const TString<TChar>& consumable )
628 {
629 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
630 TrimEnd();
631
632 if ( !base::template EndsWith<CHK,TSensitivity>( consumable ) )
633 return false;
634 base::length-= consumable.Length();
635 return true;
636 }
637
638 //==============================================================================================
639 /// Consumes a minimum of \p{minChars} of string \p{consumable} from the start of this
640 /// substring. If the minimum characters could not be found, nothing is consumed, otherwise,
641 /// the method consumes as much as possible.<br>
642 ///
643 /// This method is useful read "tokens" from a string that may be abbreviated.
644 /// Within \alib this method is for example used with
645 /// \ref alib_enums_records_details_serialization "deserialization of enumeration elements".
646 ///
647 /// @tparam TSensitivity The sensitivity of the comparison.
648 /// Defaults to \b Case::Ignore.
649 /// @tparam TTrimBeforeConsume Determines if the string should be (left-) trimmed before the
650 /// first character consume operation.
651 /// Defaults to \b Whitespaces::Keep.
652 /// @param consumable The consumable string.
653 /// @param minChars The minimum amount of characters to consume. If \c 0 or
654 /// negative, the length of \p{consumable} is chosen.
655 /// Optional and defaults to \c 1.
656 /// @return The amount of characters consumed.
657 //==============================================================================================
658 template< lang::Case TSensitivity= lang::Case::Ignore,
659 lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep >
661 int minChars = 1 )
662 {
663 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
664 TrimStart();
665 if ( minChars <= 0 )
666 minChars= static_cast<int>( consumable.Length() );
667
668 if ( minChars == 0 || minChars > consumable.Length() )
669 return 0;
670
671 integer diff= base::IndexOfFirstDifference( consumable, TSensitivity );
672 if( diff < static_cast<integer>( minChars ) )
673 return 0;
674 ConsumeChars( diff );
675 return diff;
676 }
677
678 //==============================================================================================
679 /// Consumes a field from the beginning of this substring, which is surrounded by
680 /// given start end end character identifiers. If both are the same, e.g., \c '"', then
681 /// the first occurrence of the end character is used. If they are not the same, e.g.
682 /// \c '<' and \c '>', then repeated start characters are counted and consumption only ends
683 /// when a corresponding amount of end characters has been found.
684 ///
685 /// @tparam TTrimBeforeConsume Determines if the string should be (left-) trimmed before the
686 /// consume operation. Defaults to \b Whitespaces::Keep.
687 /// @param startChar The start character of the field to consume.
688 /// @param endChar The end character of the field to consume.
689 /// @return The string consumed. \b NULL_STRING on error (start/end character not found)
690 //==============================================================================================
691 template< lang::Whitespaces TTrimBeforeConsume= lang::Whitespaces::Keep >
692 TString<TChar> ConsumeField( TChar startChar, TChar endChar )
693 {
694 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
695 TrimStart();
696
697 integer endIdx;
698 if ( base::CharAtStart() != startChar
699 || (endIdx= base::IndexOfSegmentEnd( startChar, endChar, 1)) < 0 )
700 return nullptr;
701
702
704 base result= base( base::buffer + 1, endIdx - 1 );
705 base::buffer+= (endIdx + 1);
706 base::length-= (endIdx + 1);
708 return result;
709 }
710
711
712 #if DOXYGEN
713 //==============================================================================================
714 /// Consumes all characters \c '0' to \c '9' at the start of this object and stores the
715 /// value they represent in \p{result}.<br>
716 /// Unlike methods #ConsumeInt or #ConsumeDec, this method does not consume (accept)
717 /// sign-, whitespace- or group-characters.
718 ///
719 /// @tparam TIntegral The output type.
720 /// Must be statically castable from \b uint64_t.
721 /// @param [out] result A reference to the result value.
722 ///
723 /// @return \c true if a number was found and consumed, \c false otherwise.
724 //==============================================================================================
725 template<typename TIntegral>
726 inline
727 bool ConsumeDecDigits( TIntegral& result );
728 #else
729 template<typename TIntegral>
730 ATMP_T_IF(bool, ATMP_IS_INT(TIntegral))
731 ConsumeDecDigits( TIntegral& result )
732 {
733 uint64_t resultImpl;
734 bool returnValue= consumeDecDigitsImpl( resultImpl );
735 result= static_cast<TIntegral>( resultImpl );
736 return returnValue;
737 }
738 #endif
739
740 #if DOXYGEN
741 //==============================================================================================
742 /// Consumes an integral value in decimal, binary, hexadecimal or octal format from the
743 /// string.
744 ///
745 /// Parameter \p{numberFormat} defaults to \c nullptr. This denotes static singleton
746 /// \alib{strings;TNumberFormat::Computational;NumberFormat::Computational}
747 /// which is configured to not using (not allowing) grouping characters.
748 ///
749 /// For more information on number conversion, see class
750 /// \alib{strings;TNumberFormat;NumberFormat}.
751 ///
752 /// @tparam TIntegral The output type.
753 /// Must be statically castable from \b uint64_t.
754 /// @param [out] result A reference to the result value.
755 /// @param numberFormat The number format to use. Defaults to \c nullptr.
756 /// @return \c true if a number was found and consumed, \c false otherwise.
757 //==============================================================================================
758 template<typename TIntegral>
759 inline
760 bool ConsumeInt( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr );
761 #else
762 template<typename TIntegral>
763 ATMP_T_IF(bool, ATMP_IS_INT(TIntegral) )
764 ConsumeInt( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr )
765 {
766 int64_t resultImpl;
767 bool returnValue= consumeIntImpl( resultImpl, numberFormat );
768 result= static_cast<TIntegral>( resultImpl );
769 return returnValue;
770 }
771 #endif
772
773 #if DOXYGEN
774 //==============================================================================================
775 /// Consumes an unsigned integer in standard decimal format from the start of this %AString.
776 ///
777 /// Parameter \p{numberFormat} defaults to \c nullptr. This denotes static singleton
778 /// \alib{strings;TNumberFormat::Computational;NumberFormat::Computational}
779 /// which is configured to not using (not allowing) grouping characters.
780 ///
781 /// Sign literals \c '-' or \c '+' are \b not accepted and parsing will fail.
782 /// For reading signed integral values, see methods #ConsumeInt, for floating point numbers
783 /// #ConsumeFloat.
784 ///
785 /// For more information on number conversion, see class
786 /// \alib{strings;TNumberFormat;NumberFormat}.
787 ///
788 /// @tparam TIntegral The output type.
789 /// Must be statically castable from \b uint64_t.
790 /// @param [out] result A reference to the result value.
791 /// @param numberFormat The number format to use. Defaults to \c nullptr.
792 /// @return \c true if a number was found and consumed, \c false otherwise.
793 //==============================================================================================
794 template<typename TIntegral>
795 inline
796 bool ConsumeDec( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr );
797 #else
798 template<typename TIntegral>
799 ATMP_T_IF(bool, ATMP_IS_INT(TIntegral))
800 ConsumeDec( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr )
801 {
802 uint64_t resultImpl;
803 bool returnValue= consumeDecImpl( resultImpl, numberFormat );
804 result= static_cast<TIntegral>( resultImpl );
805 return returnValue;
806 }
807 #endif
808
809 #if DOXYGEN
810 //==========================================================================================
811 /// Consumes an unsigned integer in binary format from the start of this string.
812 ///
813 /// Parameter \p{numberFormat} defaults to \c nullptr. This denotes static singleton
814 /// \alib{strings;TNumberFormat::Computational;NumberFormat::Computational}
815 /// which is configured to not using (not allowing) grouping characters.
816 ///
817 /// For more information on number conversion, see class
818 /// \alib{strings;TNumberFormat;NumberFormat}.
819 ///
820 /// @param [out] result A reference to the result value.
821 /// @param numberFormat The number format to use. Defaults to \c nullptr.
822 /// @tparam TIntegral The output type.
823 /// Must be statically castable from \b uint64_t.
824 /// @return \c true if a number was found and consumed, \c false otherwise.
825 //==========================================================================================
826 template<typename TIntegral>
827 inline
828 bool ConsumeBin( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr );
829 #else
830 template<typename TIntegral>
831 ATMP_T_IF(bool, ATMP_IS_INT(TIntegral))
832 ConsumeBin( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr )
833 {
834 uint64_t resultImpl;
835 bool returnValue= consumeBinImpl( resultImpl, numberFormat );
836 result= static_cast<TIntegral>( resultImpl );
837 return returnValue;
838 }
839 #endif
840
841 #if DOXYGEN
842 //==========================================================================================
843 /// Consumes an unsigned integer in hexadecimal format from the start of this string.
844 ///
845 /// Parameter \p{numberFormat} defaults to \c nullptr. This denotes static singleton
846 /// \alib{strings;TNumberFormat::Computational;NumberFormat::Computational}
847 /// which is configured to not using (not allowing) grouping characters.
848 ///
849 /// For more information on number conversion, see class
850 /// \alib{strings;TNumberFormat;NumberFormat}.
851 ///
852 /// @tparam TIntegral The output type.
853 /// Must be statically castable from \b uint64_t.
854 /// @param [out] result A reference to the result value.
855 /// @param numberFormat The number format to use. Defaults to \c nullptr.
856 ///
857 /// @return \c true if a number was found and consumed, \c false otherwise.
858 //==========================================================================================
859 template<typename TIntegral>
860 inline
861 bool ConsumeHex( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr );
862 #else
863 template<typename TIntegral>
864 ATMP_T_IF(bool, ATMP_IS_INT(TIntegral))
865 ConsumeHex( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr )
866 {
867 uint64_t resultImpl;
868 bool returnValue= consumeHexImpl( resultImpl, numberFormat );
869 result= static_cast<TIntegral>( resultImpl );
870 return returnValue;
871 }
872 #endif
873
874 #if DOXYGEN
875 //==========================================================================================
876 /// Consumes an unsigned integer in octal format from the start of this string.
877 ///
878 /// Parameter \p{numberFormat} defaults to \c nullptr. This denotes static singleton
879 /// \alib{strings;TNumberFormat::Computational;NumberFormat::Computational}
880 /// which is configured to not using (not allowing) grouping characters.
881 ///
882 /// For more information on number conversion, see class
883 /// \alib{strings;TNumberFormat;NumberFormat}.
884 ///
885 /// @tparam TIntegral The output type.
886 /// Must be statically castable from \b uint64_t.
887 /// @param [out] result A reference to the result value.
888 /// @param numberFormat The number format to use. Defaults to \c nullptr.
889 ///
890 /// @return \c true if a number was found and consumed, \c false otherwise.
891 //==========================================================================================
892 template<typename TIntegral>
893 inline
894 bool ConsumeOct( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr );
895 #else
896 template<typename TIntegral>
897 ATMP_T_IF(bool, ATMP_IS_INT(TIntegral))
898 ConsumeOct( TIntegral& result, TNumberFormat<TChar>* numberFormat= nullptr )
899 {
900 uint64_t resultImpl;
901 bool returnValue= consumeOctImpl( resultImpl, numberFormat );
902 result= static_cast<TIntegral>( resultImpl );
903 return returnValue;
904 }
905 #endif
906
907 //==============================================================================================
908 /// Consumes a floating point number from the start of this string.
909 ///
910 /// on the given \p{numberFormat} instance.<br>
911 /// Parameter \p{numberFormat} defaults to \c nullptr. This denotes static singleton
912 /// \alib{strings;TNumberFormat::Computational;NumberFormat::Computational}
913 /// which is configured to 'international' settings (not using the locale) and therefore
914 /// also not parsing grouping characters.
915 ///
916 /// For more information on parsing options for floating point numbers and number
917 /// conversion in general, see class
918 /// \alib{strings;TNumberFormat;NumberFormat}.
919 ///
920 /// @param [out] result A reference to the result value.
921 /// @param numberFormat The number format to use. Defaults to \c nullptr.
922 ///
923 /// @return \c true if a number was found and consumed, \c false otherwise.
924 //==============================================================================================
926 bool ConsumeFloat( double& result,
927 TNumberFormat<TChar>* numberFormat =nullptr );
928
929
930 //==============================================================================================
931 /// Splits this substring into two parts. What remains in this object is the region
932 /// from 0 to \p{position}.
933 /// \p{target} receives the rest. If \p{separatorWidth} is given, this is subtracted from
934 /// the front of \p{target}.
935 ///
936 /// @tparam TCheck Defaults to \alib{CHK}, which is the normal invocation mode.
937 /// If \c <false> is added to the method name, no parameter check is
938 /// performed.
939 ///
940 /// @param position The index where this object is split.
941 /// @param target The target substring to receive the right part of the string.
942 /// @param separatorWidth This does not change what remains in this object, but defines
943 /// the number of characters that are cut from the front of the
944 /// \p{target}. Defaults to 0.
945 /// @param trim If \c true, both substrings will be trimmed.
946 ///
947 /// @return \c *this to allow concatenated calls.
948 //==============================================================================================
949 template <typename TCheck= CHK>
950 TSubstring& Split( integer position, TSubstring& target, integer separatorWidth =0,
951 bool trim= false )
952
953 {
954 if constexpr ( TCheck::value )
955 base::AdjustRegion( position, separatorWidth );
956 else
957 {
958 ALIB_ASSERT_ERROR( position >=0 && position <= base::length,
959 "STRINGS", "Non checking but position out of bounds" )
960 ALIB_ASSERT_ERROR( position + separatorWidth <= base::length,
961 "STRINGS", "Non checking but position + separator width out of bounds" )
962 }
963
964 target= this->base::template Substring<NC>( position + separatorWidth,
965 base::length - position - separatorWidth );
966 base::length= position;
967 if( trim )
968 {
969 target.Trim();
970 this ->Trim();
971 }
972 return *this;
973 }
974
975 //################################################################################################
976 // Protected Methods
977 //################################################################################################
978 protected:
979 //==============================================================================================
980 /// Implementation of #ConsumeDecDigits (the non-inline part).
981 ///
982 /// @param [out] result A reference to the result value.
983 /// @return \c true if a number was found and consumed, \c false otherwise.
984 //==============================================================================================
985 ALIB_API bool consumeDecDigitsImpl( uint64_t& result );
986
987 //==============================================================================================
988 /// Implementation of #ConsumeInt (the non-inline part).
989 ///
990 /// @param [out] result A reference to the result value.
991 /// @param numberFormat The number format to use.
992 /// @return \c true if a number was found and consumed, \c false otherwise.
993 //==============================================================================================
994 ALIB_API bool consumeIntImpl( int64_t& result, TNumberFormat<TChar>* numberFormat );
995
996 //==============================================================================================
997 /// Implementation of #ConsumeDec (the non-inline part).
998 ///
999 /// @param [out] result A reference to the result value.
1000 /// @param numberFormat The number format to use.
1001 /// @return \c true if a number was found and consumed, \c false otherwise.
1002 //==============================================================================================
1003 ALIB_API bool consumeDecImpl( uint64_t& result, TNumberFormat<TChar>* numberFormat );
1004
1005 //==============================================================================================
1006 /// Implementation of #ConsumeBin (the non-inline part).
1007 ///
1008 /// @param [out] result A reference to the result value.
1009 /// @param numberFormat The number format to use.
1010 /// @return \c true if a number was found and consumed, \c false otherwise.
1011 //==============================================================================================
1012 ALIB_API bool consumeBinImpl( uint64_t& result, TNumberFormat<TChar>* numberFormat );
1013
1014 //==============================================================================================
1015 /// Implementation of #ConsumeHex (the non-inline part).
1016 ///
1017 /// @param [out] result A reference to the result value.
1018 /// @param numberFormat The number format to use.
1019 /// @return \c true if a number was found and consumed, \c false otherwise.
1020 //==============================================================================================
1021 ALIB_API bool consumeHexImpl( uint64_t& result, TNumberFormat<TChar>* numberFormat );
1022
1023 //==============================================================================================
1024 /// Implementation of #ConsumeOct (the non-inline part).
1025 ///
1026 /// @param [out] result A reference to the result value.
1027 /// @param numberFormat The number format to use.
1028 /// @return \c true if a number was found and consumed, \c false otherwise.
1029 //==============================================================================================
1030 ALIB_API bool consumeOctImpl( uint64_t& result, TNumberFormat<TChar>* numberFormat );
1031}; // class TSubstring
1032
1033extern template ALIB_API bool TSubstring<nchar>::ConsumeFloat ( double& , TNumberFormat<nchar>* );
1034extern template ALIB_API bool TSubstring<nchar>::consumeDecDigitsImpl( uint64_t& );
1035extern template ALIB_API bool TSubstring<nchar>::consumeIntImpl ( int64_t& , TNumberFormat<nchar>* );
1036extern template ALIB_API bool TSubstring<nchar>::consumeDecImpl ( uint64_t& , TNumberFormat<nchar>* );
1037extern template ALIB_API bool TSubstring<nchar>::consumeBinImpl ( uint64_t& , TNumberFormat<nchar>* );
1038extern template ALIB_API bool TSubstring<nchar>::consumeHexImpl ( uint64_t& , TNumberFormat<nchar>* );
1039extern template ALIB_API bool TSubstring<nchar>::consumeOctImpl ( uint64_t& , TNumberFormat<nchar>* );
1040
1041extern template ALIB_API bool TSubstring<wchar>::ConsumeFloat ( double& , TNumberFormat<wchar>* );
1042extern template ALIB_API bool TSubstring<wchar>::consumeDecDigitsImpl( uint64_t& );
1043extern template ALIB_API bool TSubstring<wchar>::consumeIntImpl ( int64_t& , TNumberFormat<wchar>* );
1044extern template ALIB_API bool TSubstring<wchar>::consumeDecImpl ( uint64_t& , TNumberFormat<wchar>* );
1045extern template ALIB_API bool TSubstring<wchar>::consumeBinImpl ( uint64_t& , TNumberFormat<wchar>* );
1046extern template ALIB_API bool TSubstring<wchar>::consumeHexImpl ( uint64_t& , TNumberFormat<wchar>* );
1047extern template ALIB_API bool TSubstring<wchar>::consumeOctImpl ( uint64_t& , TNumberFormat<wchar>* );
1048
1049extern template ALIB_API bool TSubstring<xchar>::ConsumeFloat ( double& , TNumberFormat<xchar>* );
1050extern template ALIB_API bool TSubstring<xchar>::consumeDecDigitsImpl( uint64_t& );
1051extern template ALIB_API bool TSubstring<xchar>::consumeIntImpl ( int64_t& , TNumberFormat<xchar>* );
1052extern template ALIB_API bool TSubstring<xchar>::consumeDecImpl ( uint64_t& , TNumberFormat<xchar>* );
1053extern template ALIB_API bool TSubstring<xchar>::consumeBinImpl ( uint64_t& , TNumberFormat<xchar>* );
1054extern template ALIB_API bool TSubstring<xchar>::consumeHexImpl ( uint64_t& , TNumberFormat<xchar>* );
1055extern template ALIB_API bool TSubstring<xchar>::consumeOctImpl ( uint64_t& , TNumberFormat<xchar>* );
1056
1057} // namespace alib::[strings]
1058
1059/// Type alias in namespace \b alib.
1060using Substring = strings::TSubstring<character>;
1061
1062/// Type alias in namespace \b alib.
1063using NSubstring = strings::TSubstring<nchar>;
1064
1065/// Type alias in namespace \b alib.
1066using WSubstring = strings::TSubstring<wchar>;
1067
1068/// Type alias in namespace \b alib.
1069using XSubstring = strings::TSubstring<xchar>;
1070
1071} // namespace [alib]
1072
1073#endif // HPP_ALIB_STRINGS_SUBSTRING
1074
TAString & _(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
constexpr bool IsEmpty() const
Definition string.hpp:383
const TChar * buffer
Definition string.hpp:117
integer IndexOfSegmentEnd(TChar opener, TChar closer, integer idx) const
constexpr integer Length() const
Definition string.hpp:326
integer IndexOfFirstDifference(const TString &needle, lang::Case sensitivity=lang::Case::Sensitive, integer startIdx=0) const
Definition string.hpp:1225
TChar CharAtStart() const
Definition string.hpp:466
constexpr bool IsNotNull() const
Definition string.hpp:371
bool AdjustRegion(integer &regionStart, integer &regionLength) const
Definition string.hpp:2061
integer IndexOfOrLength(TChar needle) const
Definition string.hpp:972
TChar CharAtEnd() const
Definition string.hpp:488
bool EndsWith(const TString &needle) const
Definition string.hpp:854
bool StartsWith(const TString &needle) const
Definition string.hpp:820
constexpr TString() noexcept=default
Defaulted default constructor.
bool ConsumeStringFromEnd(const TString< TChar > &consumable)
ALIB_API bool consumeDecDigitsImpl(uint64_t &result)
Definition substring.cpp:23
TSubstring()
Default constructor creating a 6.1 Nulled Strings "nulled" substring.
Definition substring.hpp:60
ALIB_API bool consumeBinImpl(uint64_t &result, TNumberFormat< TChar > *numberFormat)
Definition substring.cpp:68
TString< TChar > ConsumeField(TChar startChar, TChar endChar)
bool ConsumeString(const TString< TChar > &consumable)
TSubstring & Split(integer position, TSubstring &target, integer separatorWidth=0, bool trim=false)
TSubstring & TrimEnd(const TCString< TChar > &whiteSpaces=TT_CStringConstants< TChar >::DefaultWhitespaces())
bool ConsumeOct(TIntegral &result, TNumberFormat< TChar > *numberFormat=nullptr)
bool ConsumeHex(TIntegral &result, TNumberFormat< TChar > *numberFormat=nullptr)
ALIB_API bool ConsumeFloat(double &result, TNumberFormat< TChar > *numberFormat=nullptr)
TSubstring(const TString< TChar > &src)
Definition substring.hpp:68
integer ConsumeCharsFromEnd(integer regionLength, TSubstring *target=nullptr)
integer ConsumePartOf(const TString< TChar > &consumable, int minChars=1)
integer ConsumeChars(integer regionLength, TSubstring *target=nullptr)
TSubstring & TrimStart(const TCString< TChar > &whiteSpaces=TT_CStringConstants< TChar >::DefaultWhitespaces())
Definition substring.hpp:89
bool ConsumeBin(TIntegral &result, TNumberFormat< TChar > *numberFormat=nullptr)
bool ConsumeDec(TIntegral &result, TNumberFormat< TChar > *numberFormat=nullptr)
TString< TChar > base
The base string-type.
Definition substring.hpp:48
bool ConsumeDecDigits(TIntegral &result)
bool ConsumeInt(TIntegral &result, TNumberFormat< TChar > *numberFormat=nullptr)
integer ConsumeCharsFromEnd(integer regionLength, AString &target, integer separatorWidth=0)
ALIB_API bool consumeHexImpl(uint64_t &result, TNumberFormat< TChar > *numberFormat)
Definition substring.cpp:84
integer ConsumeChars(integer regionLength, TString< TChar > &target, integer separatorWidth=0)
TString< TChar > ConsumeToken(TChar separator=',', lang::Inclusion includeSeparator=lang::Inclusion::Include)
ALIB_API bool consumeIntImpl(int64_t &result, TNumberFormat< TChar > *numberFormat)
Definition substring.cpp:36
ALIB_API bool consumeDecImpl(uint64_t &result, TNumberFormat< TChar > *numberFormat)
Definition substring.cpp:52
ALIB_API bool consumeOctImpl(uint64_t &result, TNumberFormat< TChar > *numberFormat)
bool ConsumeCharFromEnd(TChar consumable)
TSubstring & Trim(const TCString< TChar > &whiteSpaces=TT_CStringConstants< TChar >::DefaultWhitespaces())
bool ConsumeChar(TChar consumable)
integer ConsumeChars(integer regionLength, TAString< TChar, TAllocator > &target, integer separatorWidth=0)
#define ATMP_IS_INT(T)
Definition tmp.hpp:24
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_API
Definition alib.hpp:639
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:760
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:49
integer IndexOfAnyExcluded(const TChar *haystack, integer haystackLength, const TChar *needles, integer needlesLength)
TChar ToUpper(TChar c)
integer LastIndexOfAnyExclude(const TChar *haystack, integer startIdx, const TChar *needles, integer needlesLength)
Inclusion
Denotes how members of a set something should be taken into account.
@ Include
Chooses inclusion.
Whitespaces
Denotes whether a string is trimmed or not.
@ Keep
Keep whitespaces in string.
@ Trim
Trim whitespaces away.
@ Clear
Chooses to clear existing data.
Case
Denotes upper and lower case character treatment.
Definition alib.cpp:69
strings::TSubstring< character > Substring
Type alias in namespace alib.
strings::TSubstring< nchar > NSubstring
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
strings::TSubstring< wchar > WSubstring
Type alias in namespace alib.
strings::TSubstring< xchar > XSubstring
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:273
See sibling type NC.
Definition alib.hpp:1097