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