41 string_view hexmap() noexcept ;
42 bool isDigit(
char c ) noexcept ;
43 bool isHex(
char c ) noexcept ;
44 bool isPrintableAscii(
char c ) noexcept ;
45 bool isPrintable(
char c ) noexcept ;
46 bool isSimple(
char c ) noexcept ;
47 char toLower(
char c ) noexcept ;
48 char toUpper(
char c ) noexcept ;
49 unsigned short toUShort( string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
50 unsigned long toULong( string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
51 unsigned long toULongHex( string_view ,
bool limited ) ;
52 unsigned int toUInt( string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
53 short toShort( string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
54 long toLong( string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
55 int toInt( string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
56 template <typename U> string_view fromUnsignedToHex( U u ,
char * out_p ) noexcept ;
57 void strncpy(
char * , const
char * ,
std::
size_t ) noexcept ;
58 template <typename Tstr, typename Fn>
bool readLine(
std::istream & , Tstr & ,
char * ,
std::
size_t , Fn ) ;
59 template <typename S, typename T, typename SV>
void splitIntoTokens( const S & in , T & out , const SV & ws ) ;
60 template <typename S, typename T>
void splitIntoTokens( const S & in , T & out , const S & ws , typename S::value_type esc ) ;
61 template <typename T>
void splitIntoFields( string_view in , T & out , string_view ws ) ;
62 template <typename T>
void splitIntoFields( string_view in_in , T & out , string_view ws ,
char escape ,
bool remove_escapes ) ;
63 bool ilessc(
char c1 ,
char c2 ) noexcept ;
64 bool imatchc(
char c1 ,
char c2 ) noexcept ;
65 bool imatch( const
std::
string & a , const
std::
string & b ) ;
66 template <typename T, typename V> T unique( T in , T end , V repeat , V replacement ) ;
69 void join( string_view ,
std::
string & , string_view ) ;
70 template <typename Tout>
std::
size_t outputHex( Tout out ,
char c ) ;
71 template <typename Tout>
std::
size_t outputHex( Tout out ,
wchar_t c ) ;
72 template <typename Tout, typename Tchar>
std::
size_t outputPrintable( Tout , Tchar , Tchar ,
char ,
bool ) ;
73 bool allOf( string_view s ,
bool (*fn)(
char) ) noexcept ;
77bool G::StrImp::allOf( string_view s ,
bool (*fn)(
char) ) noexcept
79 return std::all_of( s.begin() , s.end() , fn ) ;
85 if( s_in.empty() )
return {} ;
86 std::string s( s_in.data() , s_in.size() ) ;
94 if( s_in.empty() )
return {} ;
95 std::string s( s_in.data() , s_in.size() ) ;
96 escape( s , c_escape , specials_in , specials_out ) ;
102 G_ASSERT( specials_in.size() == specials_out.size() ) ;
103 std::size_t pos = 0U ;
107 pos = s.find_first_of( specials_in.data() , pos , specials_in.size() ) ;
108 if( pos == std::string::npos )
113 const std::size_t special_index = specials_in.find( c_in ) ;
114 char c_out = specials_out.at( special_index ) ;
116 s.insert( pos , 1U , c_escape ) ;
125 Str::escape( s ,
'\\' ,
"\0\\\r\n\t"_sv ,
"0\\rnt"_sv ) ;
130 G_ASSERT( ws.size() == nbws.size() ) ;
132 result.reserve( s.size() ) ;
133 bool in_quote = false ;
134 bool escaped = false ;
137 if( c == esc && !escaped )
140 result.append( 1U , esc ) ;
144 std::size_t wspos = 0 ;
145 if( c == qq && !escaped && !in_quote )
149 else if( c == qq && !escaped )
153 else if( in_quote && (wspos=ws.find(c)) != std::string::npos )
157 result.append( 1U , nbws.at(wspos) ) ;
161 result.append( 1U , esc ) ;
162 result.append( 1U , c ) ;
167 result.append( 1U , c ) ;
177 unescape( s ,
'\\' ,
"0rnt"_sv ,
"\0\r\n\t"_sv ) ;
182 G_ASSERT( specials_in.size() == specials_out.size() ) ;
183 bool escaped = false ;
184 std::size_t cpos = 0U ;
185 auto out = s.begin() ;
186 for(
char & c_in : s )
188 if( escaped && (cpos=specials_in.find(c_in)) != std::string::npos )
189 *out++ = specials_out.at(cpos) , escaped = false ;
190 else if( escaped && c_in == c_escape )
191 *out++ = c_escape , escaped = false ;
193 *out++ = c_in , escaped = false ;
194 else if( c_in == c_escape )
197 *out++ = c_in , escaped = false ;
199 if( out != s.end() ) s.erase( out , s.end() ) ;
205 std::string s( s_in ) ;
222 for( std::string & s : a )
223 replace( s , from , to ) ;
231 std::size_t pos = pos_p ==
nullptr ? 0 : *pos_p ;
232 if( pos >= s.size() )
235 pos = s.find( from.data() , pos , from.size() ) ;
236 if( pos == std::string::npos )
238 else if( to.empty() )
239 s.erase( pos , from.size() ) ;
241 s.replace( pos , from.size() , to.data() , to.size() ) ;
242 if( pos_p !=
nullptr )
243 *pos_p = pos + to.size() ;
249 unsigned int count = 0U ;
250 for( std::size_t pos = 0U ; replace(s,from,to,&pos) ; count++ )
257 std::string result( s ) ;
258 replaceAll( result , {&from,1U} , {&to,1U} ) ;
264 s.erase( std::remove_if( s.begin() , s.end() , [c](
char x){return x==c;} ) , s.end() ) ;
270 std::string s( s_in ) ;
279 result.reserve( s.size() ) ;
282 if( chars.find(c) != std::string::npos )
283 result.append( 1U , c ) ;
290 std::size_t n = s.find_first_not_of( ws.data() , 0U , ws.size() ) ;
291 if( limit != 0U && ( n == std::string::npos || n > limit ) )
292 n = limit >= s.size() ? std::string::npos : limit ;
293 if( n == std::string::npos )
302 std::size_t n = sv.find_first_not_of( ws ) ;
303 if( limit != 0U && ( n == std::string::npos || n > limit ) )
304 n = limit >= sv.size() ? std::string::npos : limit ;
305 if( n == std::string::npos )
306 return sv_substr( sv , 0U , 0U ) ;
308 return sv_substr( sv , n ) ;
315 std::size_t n = s.find_last_not_of( ws.data() , std::string::npos , ws.size() ) ;
316 if( limit != 0U && ( n == std::string::npos || s.size() > (limit+n+1U) ) )
317 n = limit >= s.size() ? std::string::npos : (s.size()-limit-1U) ;
318 if( n == std::string::npos )
320 else if( (n+1U) != s.size() )
327 std::size_t n = sv.find_last_not_of( ws ) ;
328 if( limit != 0U && ( n == std::string::npos || sv.size() > (limit+n+1U) ) )
329 n = limit >= sv.size() ? std::string::npos : (sv.size()-limit-1U) ;
330 if( n == std::string::npos )
331 return sv_substr( sv , 0U , 0U ) ;
332 else if( (n+1U) != sv.size() )
333 return sv_substr( sv , 0U , n+1U ) ;
340 return trimLeft( trimRight(s,ws) , ws ) ;
345 std::string s( s_in ) ;
346 return trim( s , ws ) ;
351 return std::move( trimLeft(trimRight(s,ws),ws) ) ;
356 return trimLeftView( trimRightView(s,ws) , ws ) ;
359bool G::StrImp::isDigit(
char c )
noexcept
361 auto uc =
static_cast<unsigned char>(c) ;
362 return uc >= 48U && uc <= 57U ;
365bool G::StrImp::isHex(
char c )
noexcept
367 auto uc =
static_cast<unsigned char>(c) ;
368 return ( uc >= 48U && uc <= 57U ) || ( uc >= 65U && uc <= 70U ) || ( uc >= 97U && uc <= 102U ) ;
371bool G::StrImp::isPrintableAscii(
char c )
noexcept
373 auto uc =
static_cast<unsigned char>(c) ;
374 return uc >= 32U && uc < 127U ;
377bool G::StrImp::isPrintable(
char c )
noexcept
379 auto uc =
static_cast<unsigned char>(c) ;
380 return ( uc >= 32U && uc < 127U ) || ( uc >= 0xa0 && uc < 0xff ) ;
383bool G::StrImp::isSimple(
char c )
noexcept
385 auto uc =
static_cast<unsigned char>(c) ;
386 return isDigit(c) || c ==
'-' || c ==
'_' ||
387 ( uc >= 65U && uc <= 90U ) ||
388 ( uc >= 97U && uc <= 122U ) ;
391char G::StrImp::toLower(
char c )
noexcept
393 const auto uc =
static_cast<unsigned char>(c) ;
394 return ( uc >= 65U && uc <= 90U ) ?
static_cast<char>(c+
'\x20') : c ;
397char G::StrImp::toUpper(
char c )
noexcept
399 const auto uc =
static_cast<unsigned char>(c) ;
400 return ( uc >= 97U && uc <= 122U ) ?
static_cast<char>(c-
'\x20') : c ;
405 bool bump = allow_minus_sign && s.size() > 1U && s[0] ==
'-' ;
406 return StrImp::allOf( bump?sv_substr(s,1U):s , StrImp::isDigit ) ;
412 return StrImp::allOf( s , StrImp::isHex ) ;
418 return StrImp::allOf( s , StrImp::isPrintableAscii ) ;
423 return StrImp::allOf( s , StrImp::isPrintable ) ;
428 return StrImp::allOf( s , StrImp::isSimple ) ;
433 bool overflow = false ;
434 bool invalid = false ;
435 StrImp::toInt( s , overflow , invalid ) ;
436 return !overflow && !invalid ;
442 bool overflow = false ;
443 bool invalid = false ;
444 StrImp::toUShort( s , overflow , invalid ) ;
445 return !overflow && !invalid ;
451 bool overflow = false ;
452 bool invalid = false ;
453 StrImp::toUInt( s , overflow , invalid ) ;
454 return !overflow && !invalid ;
459 bool overflow = false ;
460 bool invalid = false ;
461 StrImp::toULong( s , overflow , invalid ) ;
462 return !overflow && !invalid ;
468 return b ?
"true" :
"false" ;
475 if( std::isnan(d) )
return "nan" ;
476 if( std::isinf(d) )
return "inf" ;
477 std::ostringstream ss ;
478 ss << std::setprecision(16) << d ;
487 if( imatch( s ,
"true"_sv ) )
489 else if( imatch( s ,
"false"_sv ) )
492 throw InvalidFormat(
"expected true/false" , s ) ;
502 std::size_t end = 0U ;
503 double result = std::stod( s , &end ) ;
504 if( end != s.size() )
505 throw InvalidFormat(
"expected floating point number" , s ) ;
508 catch( std::invalid_argument & )
510 throw InvalidFormat(
"expected floating point number" , s ) ;
512 catch( std::out_of_range & )
514 throw Overflow( s ) ;
524 std::size_t end = 0U ;
525 float result = std::stof( s , &end ) ;
526 if( end != s.size() )
527 throw InvalidFormat(
"expected floating point number" , s ) ;
530 catch( std::invalid_argument & )
532 throw InvalidFormat(
"expected floating point number" , s ) ;
534 catch( std::out_of_range & )
536 throw Overflow( s ) ;
543 bool overflow = false ;
544 bool invalid = false ;
545 int result = StrImp::toInt( s , overflow , invalid ) ;
547 throw InvalidFormat(
"expected integer" , s ) ;
549 throw Overflow( s ) ;
556 return !s1.empty() && isInt(s1) ? toInt(s1) : toInt(s2) ;
560int G::StrImp::toInt(
string_view s ,
bool & overflow ,
bool & invalid )
noexcept
562 long long_val = toLong( s , overflow , invalid ) ;
563 int result =
static_cast<int>( long_val ) ;
564 if( result != long_val )
572 bool overflow = false ;
573 bool invalid = false ;
574 long result = StrImp::toLong( s , overflow , invalid ) ;
576 throw InvalidFormat(
"expected long integer" , s ) ;
578 throw Overflow( s ) ;
583long G::StrImp::toLong(
string_view s ,
bool & overflow ,
bool & invalid )
noexcept
585 bool negative = !s.empty() && s[0] ==
'-' ;
586 bool positive = !s.empty() && s[0] ==
'+' ;
587 if( (negative || positive) && s.size() == 1U )
592 unsigned long ul = toULong( sv_substr(s,(negative||positive)?1U:0U) , overflow , invalid ) ;
593 static constexpr long long_max = std::numeric_limits<long>::max() ;
594 if( ul > long_max || (negative && (ul==long_max)) )
599 return negative ? -
static_cast<long>(ul) :
static_cast<long>(ul) ;
605 bool overflow = false ;
606 bool invalid = false ;
607 short result = StrImp::toShort( s , overflow , invalid ) ;
609 throw InvalidFormat(
"expected short integer" , s ) ;
611 throw Overflow( s ) ;
616short G::StrImp::toShort(
string_view s ,
bool & overflow ,
bool & invalid )
noexcept
618 long long_val = toLong( s , overflow , invalid ) ;
619 auto result =
static_cast<short>( long_val ) ;
620 if( result != long_val )
627 return !s1.empty() && isUInt(s1) ? toUInt(s1) : toUInt(s2) ;
633 return !s.empty() && isUInt(s) ? toUInt(s) : default_ ;
640 bool overflow = false ;
641 bool invalid = false ;
642 unsigned int result = StrImp::toUInt( s , overflow , invalid ) ;
644 throw InvalidFormat(
"expected unsigned integer" , s ) ;
646 result = std::numeric_limits<unsigned int>::max() ;
653 bool overflow = false ;
654 bool invalid = false ;
655 unsigned int result = StrImp::toUInt( s , overflow , invalid ) ;
657 throw InvalidFormat(
"expected unsigned integer" , s ) ;
659 throw Overflow( s ) ;
663unsigned int G::StrImp::toUInt(
string_view s ,
bool & overflow ,
bool & invalid )
noexcept
665 unsigned long ulong_val = toULong( s , overflow , invalid ) ;
666 auto result =
static_cast<unsigned int>( ulong_val ) ;
667 if( result != ulong_val )
674 bool overflow = false ;
675 bool invalid = false ;
676 unsigned long result = StrImp::toULong( s , overflow , invalid ) ;
678 throw InvalidFormat(
"expected unsigned long integer" , s ) ;
680 result = std::numeric_limits<unsigned long>::max() ;
687 return StrImp::toULongHex( s ,
true ) ;
694 return StrImp::toULongHex( s ,
false ) ;
698unsigned long G::StrImp::toULongHex(
string_view s ,
bool limited )
700 unsigned long n = 0U ;
701 if( s.empty() )
return 0U ;
702 std::size_t i0 = s.find_first_not_of(
'0' ) ;
703 if( i0 == std::string::npos ) i0 = 0U ;
704 if( (s.size()-i0) > (
sizeof(
unsigned long)*2U) )
706 if( limited )
return ~0UL ;
707 throw Str::Overflow( s ) ;
709 for( std::size_t i = i0 ; i < s.size() ; i++ )
711 unsigned int c =
static_cast<unsigned char>(s.at(i)) ;
712 if( c >= 97U && c <= 102U ) c -= 87U ;
713 else if( c >= 65U && c <= 70U ) c -= 55U ;
714 else if( c >= 48U && c <= 57U ) c -= 48U ;
715 else throw Str::InvalidFormat(
"invalid hexadecimal" , s ) ;
724 bool overflow = false ;
725 bool invalid = false ;
726 unsigned long result = StrImp::toULong( s , overflow , invalid ) ;
728 throw InvalidFormat(
"expected unsigned long integer" , s ) ;
730 throw Overflow( s ) ;
737 return !s1.empty() && isULong(s1) ? toULong(s1) : toULong(s2) ;
741unsigned long G::StrImp::toULong(
string_view s ,
bool & overflow ,
bool & invalid )
noexcept
749 return Str::toUnsigned<unsigned long>( s.data() , s.data()+s.size() , overflow , invalid ) ;
755 bool overflow = false ;
756 bool invalid = false ;
757 unsigned short result = StrImp::toUShort( s , overflow , invalid ) ;
759 throw InvalidFormat(
"expected unsigned short integer" , s ) ;
761 result = std::numeric_limits<unsigned short>::max() ;
769 bool overflow = false ;
770 bool invalid = false ;
771 unsigned short result = StrImp::toUShort( s , overflow , invalid ) ;
773 throw InvalidFormat(
"expected unsigned short integer" , s ) ;
775 throw Overflow( s ) ;
780unsigned short G::StrImp::toUShort(
string_view s ,
bool & overflow ,
bool & invalid )
noexcept
782 unsigned long ulong_val = toULong( s , overflow , invalid ) ;
783 auto result =
static_cast<unsigned short>( ulong_val ) ;
784 if( result != ulong_val )
792 return StrImp::fromUnsignedToHex( u , out_p ) ;
799 return StrImp::fromUnsignedToHex( u , out_p ) ;
804G::string_view G::StrImp::fromUnsignedToHex( U u ,
char * out_p )
noexcept
807 static constexpr unsigned bytes =
sizeof(U) ;
808 static constexpr unsigned bits = 8U * bytes ;
809 static constexpr unsigned buffer_size = bytes * 2U ;
810 static const char * map =
"0123456789abcdef" ;
811 unsigned int shift = bits - 4U ;
813 for(
unsigned i = 0 ; i < (bytes*2U) ; i++ )
815 *out++ = map[(u>>shift) & 0xfUL] ;
818 string_view sv( out_p , buffer_size ) ;
819 return sv_substr( sv , std::min( sv.find_first_not_of(
'0') ,
static_cast<std::size_t
>(buffer_size-1U) ) ) ;
824 std::transform( s.begin() , s.end() , s.begin() , StrImp::toLower ) ;
829 std::string out = sv_to_string( in ) ;
836 std::transform( s.begin() , s.end() , s.begin() , StrImp::toUpper ) ;
841 std::string out = sv_to_string( in ) ;
848 static constexpr string_view chars_hexmap =
"0123456789abcdef"_sv ;
849 static_assert( chars_hexmap.size() == 16U ,
"" ) ;
850 return chars_hexmap ;
853template <
typename Tout>
854std::size_t G::StrImp::outputHex( Tout out ,
char c )
856 std::size_t n =
static_cast<unsigned char>( c ) ;
858 out( hexmap()[(n>>4U)%16U] ) ;
859 out( hexmap()[(n>>0U)%16U] ) ;
863template <
typename Tout>
864std::size_t G::StrImp::outputHex( Tout out ,
wchar_t c )
866 using uwchar_t =
typename std::make_unsigned<wchar_t>::type ;
867 std::size_t n =
static_cast<uwchar_t
>( c ) ;
869 out( hexmap()[(n>>12U)%16U] ) ;
870 out( hexmap()[(n>>8U)%16U] ) ;
871 out( hexmap()[(n>>4U)%16U] ) ;
872 out( hexmap()[(n>>0U)%16U] ) ;
876template <
typename Tout,
typename T
char>
877std::size_t G::StrImp::outputPrintable( Tout out , Tchar c , Tchar escape_in ,
char escape_out ,
bool eight_bit )
879 using Tuchar =
typename std::make_unsigned<Tchar>::type ;
880 const auto uc =
static_cast<Tuchar
>( c ) ;
888 else if( !eight_bit && uc >= 0x20U && uc < 0x7fU )
890 out(
static_cast<char>(c) ) ;
892 else if( eight_bit && ( uc >= 0x20U && uc != 0x7fU ) )
894 out(
static_cast<char>(c) ) ;
911 n += outputHex( out , c ) ;
919 result.reserve( in.length()*2U + 1U ) ;
921 StrImp::outputPrintable( [&result](
char cc){result.append(1U,cc);} , c , escape , escape , true ) ;
928 result.reserve( in.length()*2U + 1U ) ;
930 StrImp::outputPrintable( [&result](
char cc){result.append(1U,cc);} , c , escape , escape , true ) ;
937 result.reserve( in.length()*2U + 1U ) ;
939 StrImp::outputPrintable( [&result](
char cc){result.append(1U,cc);} , c , escape , escape , false ) ;
947 result.reserve( in.length()*2U + 1U ) ;
949 StrImp::outputPrintable( [&result](
wchar_t cc){result.append(1U,
static_cast<char>(cc));} , c , escape ,
static_cast<char>(escape) ,
false ) ;
957 readLine( stream , result , eol ,
false , 0U ) ;
962 bool pre_erase , std::size_t limit )
967 stream.setstate( std::ios_base::failbit ) ;
974 if( line.empty() && ( eol.empty() || eol.size() == 1U ) && limit == 0U )
976 std::getline( stream , line , eol.empty() ?
'\n' : eol[0] ) ;
981 const char eol_last = eol.at( eol.size()-1U ) ;
982 const std::size_t eol_size = eol.size() ;
983 bool got_eol = StrImp::readLine( stream , line ,
nullptr , limit ? limit : line.max_size() ,
984 [eol,eol_size,eol_last](std::string &s,
char c)
987 ( c == eol_last && s.size() >= eol_size ) ?
988 s.find(eol.data(),s.size()-eol_size,eol_size) == (s.size()-eol_size) :
992 line.erase( line.size() - eol.size() ) ;
998 bool pre_erase , std::size_t limit )
1000 if( eol == Eol::CrLf )
1002 return readLine( stream , line ,
"\r\n"_sv , pre_erase , limit ) ;
1006 if( pre_erase && stream.good() )
1010 bool got_eol = StrImp::readLine( stream , line , &next , limit ? limit : line.max_size() ,
1011 [](std::string &,
char c)
1013 return c ==
'\n' || c ==
'\r' ;
1017 if( line.at(line.size()-1U) ==
'\r' && next ==
'\n' )
1019 line.erase( line.size()-1U ) ;
1025template <
typename T
string,
typename Fn>
1026bool G::StrImp::readLine( std::istream & stream , Tstring & line ,
char * next_p , std::size_t limit , Fn eol_fn )
1028 bool got_eol = false ;
1029 bool got_some = false ;
1030 std::istream::sentry sentry( stream ,
true ) ;
1033 using traits = std::istream::traits_type ;
1034 std::size_t count = 0U ;
1035 int c = stream.rdbuf()->sgetc() ;
1036 while( count < limit && c != traits::eof() )
1038 line.append( 1U , traits::to_char_type(c) ) ;
1039 got_eol = eol_fn( line , traits::to_char_type(c) ) ;
1044 c = stream.rdbuf()->snextc() ;
1046 got_some = count > 0U ;
1047 if( count == limit )
1049 stream.setstate( std::ios_base::failbit ) ;
1051 else if( c == traits::eof() )
1053 stream.setstate( std::ios_base::eofbit ) ;
1058 stream.rdbuf()->sbumpc() ;
1060 *next_p = traits::to_char_type( stream.rdbuf()->sgetc() ) ;
1064 stream.setstate( std::ios_base::failbit ) ;
1068template <
typename S,
typename T,
typename SV>
1069void G::StrImp::splitIntoTokens(
const S & in , T & out ,
const SV & ws )
1071 for( std::size_t p = 0U ; p != S::npos ; )
1073 p = in.find_first_not_of( ws.data() , p , ws.size() ) ;
1076 std::size_t end = in.find_first_of( ws.data() , p , ws.size() ) ;
1077 std::size_t len = end == S::npos ? end : (end-p) ;
1078 out.push_back( in.substr(p,len) ) ;
1084template <
typename S,
typename T>
1085void G::StrImp::splitIntoTokens(
const S & in , T & out ,
const S & ws ,
typename S::value_type esc )
1087 using string_type = S ;
1088 string_type ews = ws + string_type(1U,esc) ;
1089 for( std::size_t p = 0U ; p != S::npos ; )
1092 p = in.find_first_not_of( ws.data() , p , ws.size() ) ;
1093 if( p == S::npos || ( in.at(p) == esc && (p+1) == in.size() ) )
1097 std::size_t end = in.find_first_of( ews.data() , p , ews.size() ) ;
1098 while( end != S::npos && end < in.size() && in.at(end) == esc )
1099 end = (end+2) < in.size() ? in.find_first_of( ews.data() , end+2 , ews.size() ) : S::npos ;
1102 std::size_t len = end == std::string::npos ? end : (end-p) ;
1103 string_type w( in.substr(p,len) ) ;
1106 for( std::size_t i = 0 ; esc && i < w.size() ; i++ )
1110 if( (i+1) < w.size() && ws.find(w[i+1]) != S::npos )
1117 out.push_back( w ) ;
1124 if( esc && in.find(esc) != std::string::npos )
1125 StrImp::splitIntoTokens( in , out , sv_to_string(ws) , esc ) ;
1127 StrImp::splitIntoTokens( in , out , ws ) ;
1133 splitIntoTokens( in , out , ws , esc ) ;
1137template <
typename T>
1142 std::size_t start = 0U ;
1143 std::size_t pos = 0U ;
1146 if( pos >= in.size() ) break ;
1147 pos = in.find_first_of( ws.data() , pos , ws.size() ) ;
1148 if( pos == std::string::npos ) break ;
1149 out.push_back( sv_to_string(in.substr(start,pos-start)) ) ;
1153 out.push_back( sv_to_string(in.substr(start,pos-start)) ) ;
1157template <
typename T>
1158void G::StrImp::splitIntoFields( string_view in_in , T & out , string_view ws ,
1159 char escape ,
bool remove_escapes )
1162 ews.reserve( ws.size() + 1U ) ;
1163 ews.assign( ws.data() , ws.size() ) ;
1164 if( escape !=
'\0' ) ews.append( 1U , escape ) ;
1165 if( !in_in.empty() )
1167 std::string in = sv_to_string( in_in ) ;
1168 std::size_t start = 0U ;
1169 std::size_t pos = 0U ;
1172 if( pos >= in.size() ) break ;
1173 pos = in.find_first_of( ews , pos ) ;
1174 if( pos == std::string::npos ) break ;
1175 if( in.at(pos) == escape )
1177 if( remove_escapes )
1178 in.erase( pos , 1U ) ;
1185 out.push_back( in.substr(start,pos-start) ) ;
1190 out.push_back( in.substr(start,pos-start) ) ;
1195 char escape ,
bool remove_escapes )
1197 StrImp::splitIntoFields( in , out ,
string_view(&sep,1U) , escape , remove_escapes ) ;
1203 StrImp::splitIntoFields( in , out ,
string_view(&sep,1U) ) ;
1211 std::string result ;
1213 for(
const auto & map_item : map )
1215 .append(sep.data(),(n++)?sep.size():0U)
1216 .append(map_item.first)
1217 .append(pre.data(),pre.size())
1218 .append(map_item.second)
1219 .append(post.data(),post.size()) ;
1226 std::string result ;
1228 for(
const auto & item : strings )
1230 .append(sep.data(),(n++)?sep.size():0U)
1239 std::string result ;
1240 StrImp::join( sep , result , s1 ) ;
1241 StrImp::join( sep , result , s2 ) ;
1242 StrImp::join( sep , result , s3 ) ;
1243 StrImp::join( sep , result , s4 ) ;
1244 StrImp::join( sep , result , s5 ) ;
1245 StrImp::join( sep , result , s6 ) ;
1246 StrImp::join( sep , result , s7 ) ;
1247 StrImp::join( sep , result , s8 ) ;
1248 StrImp::join( sep , result , s9 ) ;
1254 if( !result.empty() && !s.empty() )
1255 result.append( sep.data() , sep.size() ) ;
1256 result.append( s.data() , s.size() ) ;
1262 result.reserve( map.size() ) ;
1263 std::transform( map.begin() , map.end() , std::back_inserter(result) ,
1264 [](
const StringMap::value_type & pair){return pair.first;} ) ;
1270 static constexpr string_view chars_ws =
" \t\n\r"_sv ;
1271 static_assert( chars_ws.size() == 4U ,
"" ) ;
1278 return sv_substr( alnum_() , 0U , alnum_().size()-1U ) ;
1284 static constexpr string_view chars_alnum_ =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_"_sv ;
1285 static_assert( chars_alnum_.size() == 26U+10U+26U+1U ,
"" ) ;
1286 return chars_alnum_ ;
1292 static constexpr string_view chars_meta =
"~<>[]*$|?\\(){}\"`'&;="_sv ;
1300 pos == std::string::npos ?
1301 sv_to_string(default_) :
1302 ( pos == 0U ? std::string() : sv_to_string( pos >= in.size() ? in : in.substr(0U,pos) ) ) ;
1307 std::size_t pos = sep.empty() ? std::string::npos : in.find( sep ) ;
1308 return head( in , pos , default_empty ?
string_view() : in ) ;
1314 pos == std::string::npos ?
1316 ( pos == 0U ?
string_view(in.data(),std::size_t(0U)) : ( pos >= in.size() ? in : sv_substr(in,0U,pos) ) ) ;
1321 std::size_t pos = sep.empty() ? std::string::npos : in.find( sep ) ;
1322 return headView( in , pos , default_empty ?
string_view(in.data(),std::size_t(0U)) : in ) ;
1328 pos == std::string::npos ?
1329 sv_to_string(default_) :
1330 ( (pos+1U) >= in.size() ? std::string() : sv_to_string(in.substr(pos+1U)) ) ;
1335 std::size_t pos = sep.empty() ? std::string::npos : in.find(sep) ;
1336 if( pos != std::string::npos ) pos += (sep.size()-1U) ;
1337 return tail( in , pos , default_empty ?
string_view() : in ) ;
1343 pos == std::string::npos ?
1345 ( (pos+1U) >= in.size() ?
string_view() : sv_substr(in,pos+1U) ) ;
1350 std::size_t pos = sep.empty() ? std::string::npos : in.find(sep) ;
1351 if( pos != std::string::npos ) pos += (sep.size()-1U) ;
1352 return tailView( in , pos , default_empty ?
string_view() : in ) ;
1359 ( in.size() >= tail.size() && 0 == in.compare(in.size()-tail.size(),tail.size(),tail.data()) ) ;
1366 ( in.size() >= head.size() && 0 == in.compare(0U,head.size(),head.data()) ) ;
1382 return !s.empty() && (
1383 sv_imatch(s,
"y"_sv) || sv_imatch(s,
"yes"_sv) || sv_imatch(s,
"t"_sv) ||
1384 sv_imatch(s,
"true"_sv) || sv_imatch(s,
"1"_sv) || sv_imatch(s,
"on"_sv) ) ;
1390 return !s.empty() && (
1391 sv_imatch(s,
"n"_sv) || sv_imatch(s,
"no"_sv) || sv_imatch(s,
"f"_sv) ||
1392 sv_imatch(s,
"false"_sv) || sv_imatch(s,
"0"_sv) || sv_imatch(s,
"off"_sv) ) ;
1400bool G::StrImp::ilessc(
char c1 ,
char c2 )
noexcept
1402 if( c1 >=
'a' && c1 <=
'z' ) c1 -=
'\x20' ;
1403 if( c2 >=
'a' && c2 <=
'z' ) c2 -=
'\x20' ;
1409 return std::lexicographical_compare( a.begin() , a.end() , b.begin() , b.end() , StrImp::ilessc ) ;
1412bool G::StrImp::imatchc(
char c1 ,
char c2 )
noexcept
1420 return StrImp::imatchc( c1 , c2 ) ;
1426 return sv_imatch( a , b ) ;
1430bool G::StrImp::imatch(
const std::string & a ,
const std::string & b )
1438 return ifindat( s , key , 0U ) ;
1443 if( s.empty() || key.empty() || pos >= s.size() )
return std::string::npos ;
1444 auto p = std::search( s.data()+pos , s.data()+s.size() , key.data() , key.data()+key.size() , StrImp::imatchc ) ;
1445 return p == s.end() ? std::string::npos : std::distance(s.begin(),p) ;
1448template <
typename T,
typename V>
1449T G::StrImp::unique( T in , T end , V repeat , V replacement )
1455 T in_next = in ; ++in_next ;
1456 if( *in == repeat && in_next != end && *in_next == repeat )
1458 while( in != end && *in == repeat )
1460 *out++ = replacement ;
1472 std::string s( s_in ) ;
1473 s.erase( StrImp::unique( s.begin() , s.end() , c , r ) , s.end() ) ;
1479 return s.find(c) == std::string::npos ? s : unique( s , c , c ) ;
1482void G::StrImp::strncpy(
char * dst ,
const char * src , std::size_t n )
noexcept
1485 for( ; n ; n-- , dst++ , src++ )
1493errno_t
G::Str::strncpy_s(
char * dst , std::size_t n_dst ,
const char * src , std::size_t count )
noexcept
1495 if( dst ==
nullptr || n_dst == 0U )
1498 if( src ==
nullptr )
1504 std::size_t n = std::strlen( src ) ;
1505 if( count != truncate && count < n )
1508 if( count == truncate && n >= n_dst )
1510 StrImp::strncpy( dst , src , n_dst ) ;
1511 dst[n_dst-1U] =
'\0' ;
1514 else if( n >= n_dst )
1521 StrImp::strncpy( dst , src , n ) ;
static bool isPrintableAscii(string_view s) noexcept
Returns true if every character is a 7-bit, non-control character (ie.
static std::size_t ifind(string_view s, string_view key)
Returns the position of the key in 's' using a seven-bit case-insensitive search.
static string_view headView(string_view in, std::size_t pos, string_view default_={}) noexcept
Like head() but returning a view into the input string.
static bool match(string_view, string_view) noexcept
Returns true if the two strings are the same.
static bool replace(std::string &s, string_view from, string_view to, std::size_t *pos_p=nullptr)
A string_view overload.
static bool isUShort(string_view s) noexcept
Returns true if the string can be converted into an unsigned short without throwing an exception.
static string_view tailView(string_view in, std::size_t pos, string_view default_={}) noexcept
Like tail() but returning a view into the input string.
static unsigned int toUInt(string_view s)
Converts string 's' to an unsigned int.
static string_view alnum() noexcept
Returns a string of seven-bit alphanumeric characters, ie A-Z, a-z and 0-9.
static void toLower(std::string &s)
Replaces all seven-bit upper-case characters in string 's' by lower-case characters.
static bool isNumeric(string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
static short toShort(string_view s)
Converts string 's' to a short.
static StringArray keys(const StringMap &string_map)
Extracts the keys from a map of strings.
static float toFloat(const std::string &s)
Converts string 's' to a float.
static std::istream & readLine(std::istream &stream, std::string &result, string_view eol={}, bool pre_erase_result=true, std::size_t limit=0U)
Reads a line from the stream using the given line terminator, which may be multi-character.
static int toInt(string_view s)
Converts string 's' to an int.
static bool isHex(string_view s) noexcept
Returns true if every character is a hexadecimal digit.
static std::string positive()
Returns a default positive string. See isPositive().
static unsigned int replaceAll(std::string &s, string_view from, string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
static bool iless(string_view, string_view) noexcept
Returns true if the first string is lexicographically less than the first, after seven-bit lower-case...
static unsigned short toUShort(string_view s, Limited)
Converts string 's' to an unsigned short.
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
static bool tailMatch(const std::string &in, string_view ending) noexcept
Returns true if the string has the given ending (or the given ending is empty).
static std::size_t ifindat(string_view s, string_view key, std::size_t pos)
Returns the position of the key in 's' at of after position 'pos' using a seven-bit case-insensitive ...
static bool isPrintable(string_view s) noexcept
Returns true if every character is a non-control character (ie.
static std::string unescaped(const std::string &s)
Returns the unescape()d version of s.
static double toDouble(const std::string &s)
Converts string 's' to a double.
static std::string replaced(const std::string &s, char from, char to)
Returns the string 's' with all occurrences of 'from' replaced by 'to'.
static std::string fromBool(bool b)
Converts boolean 'b' to a string.
static std::string & trimLeft(std::string &s, string_view ws, std::size_t limit=0U)
Trims the lhs of s, taking off up to 'limit' of the 'ws' characters.
static void splitIntoTokens(const std::string &in, StringArray &out, string_view ws, char esc='\0')
Splits the string into 'ws'-delimited tokens.
static std::string toPrintableAscii(const std::string &in, char escape='\\')
Returns a 7-bit printable representation of the given input string.
static string_view trimmedView(string_view s, string_view ws) noexcept
Returns a trim()med view of the input view.
static std::string unique(const std::string &s, char c, char r)
Returns a string with repeated 'c' characters replaced by one 'r' character.
static long toLong(string_view s)
Converts string 's' to a long.
static string_view alnum_() noexcept
Returns alnum() with an additional trailing underscore character.
static string_view fromULongToHex(unsigned long, char *out) noexcept
Low-level conversion from an unsigned value to a lower-case hex string with no leading zeros.
static string_view meta() noexcept
Returns a list of shell meta-characters with a tilde as the first character.
static std::string join(string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
static bool isULong(string_view s) noexcept
Returns true if the string can be converted into an unsigned long without throwing an exception.
static void removeAll(std::string &, char)
Removes all occurrences of the character from the string. See also only().
static std::string lower(string_view)
Returns a copy of 's' in which all seven-bit upper-case characters have been replaced by lower-case c...
static std::string readLineFrom(std::istream &stream, string_view eol={})
Reads a line from the stream using the given line terminator.
static std::string negative()
Returns a default negative string. See isNegative().
static std::string only(string_view allow_chars, string_view s)
Returns the 's' with all occurrences of the characters not appearing in the first string deleted.
static bool isUInt(string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static std::string & trimRight(std::string &s, string_view ws, std::size_t limit=0U)
Trims the rhs of s, taking off up to 'limit' of the 'ws' characters.
static std::string removedAll(const std::string &, char)
Removes all occurrences of the character from the string and returns the result.
static std::string dequote(const std::string &, char qq='\"' , char esc = '\\' , string_view ws = Str::ws() , string_view nbws = Str::ws() )
Dequotes a string by removing unescaped quotes and escaping quoted whitespace, so "qq-aaa-esc-qq-bbb-...
static std::string printable(const std::string &in, char escape='\\')
Returns a printable representation of the given input string, using chacter code ranges 0x20 to 0x7e ...
static bool isPositive(string_view) noexcept
Returns true if the string has a positive meaning, such as "1", "true", "yes".
static bool isSimple(string_view s) noexcept
Returns true if every character is alphanumeric or "-" or "_".
static bool isNegative(string_view) noexcept
Returns true if the string has a negative meaning, such as "0", "false", "no".
static std::string upper(string_view)
Returns a copy of 's' in which all seven-bit lower-case characters have been replaced by upper-case c...
static void unescape(std::string &s, char c_escape, string_view specials_in, string_view specials_out)
Unescapes the string by replacing e-e with e, e-special-in with special-out, and e-other with other.
static bool isInt(string_view s) noexcept
Returns true if the string can be converted into an integer without throwing an exception.
static void toUpper(std::string &s)
Replaces all seven-bit lower-case characters in string 's' by upper-case characters.
static unsigned long toULong(string_view s, Limited)
Converts string 's' to an unsigned long.
static std::string fromDouble(double d)
Converts double 'd' to a string.
static std::string tail(string_view in, std::size_t pos, string_view default_={})
Returns the last part of the string after the given position.
static std::string head(string_view in, std::size_t pos, string_view default_={})
Returns the first part of the string up to just before the given position.
static void splitIntoFields(string_view in, StringArray &out, char sep, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
static string_view fromULongLongToHex(unsigned long long, char *out) noexcept
Low-level conversion from an unsigned value to a lower-case hex string with no leading zeros.
static errno_t strncpy_s(char *dst, std::size_t n_dst, const char *src, std::size_t count) noexcept
Does the same as windows strncpy_s().
static std::string trimmed(const std::string &s, string_view ws)
Returns a trim()med version of s.
static bool toBool(string_view s)
Converts string 's' to a bool.
static bool headMatch(const std::string &in, string_view head) noexcept
Returns true if the string has the given start (or head is empty).
static string_view trimLeftView(string_view, string_view ws, std::size_t limit=0U) noexcept
Trims the lhs of s, taking off up to 'limit' of the 'ws' characters.
static string_view ws() noexcept
Returns a string of standard whitespace characters.
static void escape(std::string &s, char c_escape, string_view specials_in, string_view specials_out)
Prefixes each occurrence of one of the special-in characters with the escape character and its corres...
static string_view trimRightView(string_view sv, string_view ws, std::size_t limit=0U) noexcept
Trims the rhs of s, taking off up to 'limit' of the 'ws' characters.
static std::string escaped(string_view, char c_escape, string_view specials_in, string_view specials_out)
Returns the escape()d string.
static std::string & trim(std::string &s, string_view ws)
Trims both ends of s, taking off any of the 'ws' characters.
A class like c++17's std::string_view.
std::vector< std::string > StringArray
A std::vector of std::strings.
std::map< std::string, std::string > StringMap
A std::map of std::strings.
Overload discrimiator for G::Str::toUWhatever() indicating hexadecimal strings.
Overload discrimiator for G::Str::toUWhatever() requesting a range-limited result.