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