41 std::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(
std::string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
50 unsigned long toULong(
std::string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
51 unsigned long toULongHex(
std::string_view ,
bool limited ) ;
52 unsigned int toUInt(
std::string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
53 short toShort(
std::string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
54 long toLong(
std::string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
55 int toInt(
std::string_view ,
bool & overflow ,
bool & invalid ) noexcept ;
56 template <typename U>
std::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(
std::string_view in , T & out ,
std::string_view ws ) ;
62 template <typename T>
void splitIntoFields(
std::string_view in_in , T & out ,
std::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(
std::string_view ,
std::
string & ,
std::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(
std::string_view s ,
bool (*fn)(
char) ) noexcept ;
77bool G::StrImp::allOf(
std::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() ) ;
92std::string
G::Str::escaped( std::string_view s_in ,
char c_escape , std::string_view specials_in , std::string_view specials_out )
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 ) ;
100void G::Str::escape( std::string & s ,
char c_escape , std::string_view specials_in , std::string_view 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 ) ;
128std::string
G::Str::dequote(
const std::string & s ,
char qq ,
char esc , std::string_view ws , std::string_view nbws )
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 ) ;
180void G::Str::unescape( std::string & s ,
char c_escape , std::string_view specials_in , std::string_view specials_out )
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 ) ;
226bool G::Str::replace( std::string & s , std::string_view from , std::string_view to , std::size_t * pos_p )
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_noexcept( sv , 0U , 0U ) ;
308 return sv_substr_noexcept( 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_noexcept( sv , 0U , 0U ) ;
332 else if( (n+1U) != sv.size() )
333 return sv_substr_noexcept( sv , 0U , n+1U ) ;
340 return trimLeft( trimRight(s,ws) , ws ) ;
345 std::string s( s_in ) ;
346 trimRight( s , ws ) ;
353 return trimLeftView( trimRightView(s,ws) , ws ) ;
356bool G::StrImp::isDigit(
char c )
noexcept
358 unsigned int uc =
static_cast<unsigned char>(c) ;
359 return uc >= 48U && uc <= 57U ;
362bool G::StrImp::isHex(
char c )
noexcept
364 unsigned int uc =
static_cast<unsigned char>(c) ;
365 return ( uc >= 48U && uc <= 57U ) || ( uc >= 65U && uc <= 70U ) || ( uc >= 97U && uc <= 102U ) ;
368bool G::StrImp::isPrintableAscii(
char c )
noexcept
370 unsigned int uc =
static_cast<unsigned char>(c) ;
371 return uc >= 32U && uc < 127U ;
374bool G::StrImp::isPrintable(
char c )
noexcept
376 unsigned int uc =
static_cast<unsigned char>(c) ;
377 return uc >= 32U && uc != 127U ;
380bool G::StrImp::isSimple(
char c )
noexcept
382 unsigned int uc =
static_cast<unsigned char>(c) ;
383 return isDigit(c) || c ==
'-' || c ==
'_' ||
384 ( uc >= 65U && uc <= 90U ) ||
385 ( uc >= 97U && uc <= 122U ) ;
388char G::StrImp::toLower(
char c )
noexcept
390 const auto uc =
static_cast<unsigned char>(c) ;
391 return ( uc >= 65U && uc <= 90U ) ?
static_cast<char>(c+
'\x20') : c ;
394char G::StrImp::toUpper(
char c )
noexcept
396 const auto uc =
static_cast<unsigned char>(c) ;
397 return ( uc >= 97U && uc <= 122U ) ?
static_cast<char>(c-
'\x20') : c ;
402 bool bump = allow_minus_sign && s.size() > 1U && s[0] ==
'-' ;
403 return StrImp::allOf( bump?sv_substr_noexcept(s,1U):s , StrImp::isDigit ) ;
409 return StrImp::allOf( s , StrImp::isHex ) ;
415 return StrImp::allOf( s , StrImp::isPrintableAscii ) ;
420 return StrImp::allOf( s , StrImp::isPrintable ) ;
425 return StrImp::allOf( s , StrImp::isSimple ) ;
430 bool overflow = false ;
431 bool invalid = false ;
432 StrImp::toInt( s , overflow , invalid ) ;
433 return !overflow && !invalid ;
439 bool overflow = false ;
440 bool invalid = false ;
441 StrImp::toUShort( s , overflow , invalid ) ;
442 return !overflow && !invalid ;
448 bool overflow = false ;
449 bool invalid = false ;
450 StrImp::toUInt( s , overflow , invalid ) ;
451 return !overflow && !invalid ;
456 bool overflow = false ;
457 bool invalid = false ;
458 StrImp::toULong( s , overflow , invalid ) ;
459 return !overflow && !invalid ;
465 return b ?
"true" :
"false" ;
472 if( std::isnan(d) )
return "nan" ;
473 if( std::isinf(d) )
return "inf" ;
474 std::ostringstream ss ;
475 ss << std::setprecision(16) << d ;
484 if( imatch( s ,
"true"_sv ) )
486 else if( imatch( s ,
"false"_sv ) )
489 throw InvalidFormat(
"expected true/false" , s ) ;
499 std::size_t end = 0U ;
500 double result = std::stod( s , &end ) ;
501 if( end != s.size() )
502 throw InvalidFormat(
"expected floating point number" , s ) ;
505 catch( std::invalid_argument & )
507 throw InvalidFormat(
"expected floating point number" , s ) ;
509 catch( std::out_of_range & )
511 throw Overflow( s ) ;
521 std::size_t end = 0U ;
522 float result = std::stof( s , &end ) ;
523 if( end != s.size() )
524 throw InvalidFormat(
"expected floating point number" , s ) ;
527 catch( std::invalid_argument & )
529 throw InvalidFormat(
"expected floating point number" , s ) ;
531 catch( std::out_of_range & )
533 throw Overflow( s ) ;
540 bool overflow = false ;
541 bool invalid = false ;
542 int result = StrImp::toInt( s , overflow , invalid ) ;
544 throw InvalidFormat(
"expected integer" , s ) ;
546 throw Overflow( s ) ;
553 return !s1.empty() && isInt(s1) ? toInt(s1) : toInt(s2) ;
557int G::StrImp::toInt( std::string_view s ,
bool & overflow ,
bool & invalid )
noexcept
559 long long_val = toLong( s , overflow , invalid ) ;
560 int result =
static_cast<int>( long_val ) ;
561 if( result != long_val )
569 bool overflow = false ;
570 bool invalid = false ;
571 long result = StrImp::toLong( s , overflow , invalid ) ;
573 throw InvalidFormat(
"expected long integer" , s ) ;
575 throw Overflow( s ) ;
580long G::StrImp::toLong( std::string_view s ,
bool & overflow ,
bool & invalid )
noexcept
582 bool negative = !s.empty() && s[0] ==
'-' ;
583 bool positive = !s.empty() && s[0] ==
'+' ;
584 if( (negative || positive) && s.size() == 1U )
589 unsigned long ul = toULong( sv_substr_noexcept(s,(negative||positive)?1U:0U) , overflow , invalid ) ;
590 static constexpr long long_max = std::numeric_limits<long>::max() ;
591 if( ul > long_max || (negative && (ul==long_max)) )
596 return negative ? -
static_cast<long>(ul) :
static_cast<long>(ul) ;
602 bool overflow = false ;
603 bool invalid = false ;
604 short result = StrImp::toShort( s , overflow , invalid ) ;
606 throw InvalidFormat(
"expected short integer" , s ) ;
608 throw Overflow( s ) ;
613short G::StrImp::toShort( std::string_view s ,
bool & overflow ,
bool & invalid )
noexcept
615 long long_val = toLong( s , overflow , invalid ) ;
616 auto result =
static_cast<short>( long_val ) ;
617 if( result != long_val )
624 return !s1.empty() && isUInt(s1) ? toUInt(s1) : toUInt(s2) ;
627unsigned int G::Str::toUInt( std::string_view s ,
unsigned int default_ )
noexcept
629 bool overflow = false ;
630 bool invalid = false ;
631 return !s.empty() && isUInt(s) ? StrImp::toUInt(s,overflow,invalid) : default_ ;
637 bool overflow = false ;
638 bool invalid = false ;
639 unsigned int result = StrImp::toUInt( s , overflow , invalid ) ;
641 throw InvalidFormat(
"expected unsigned integer" , s ) ;
643 result = std::numeric_limits<unsigned int>::max() ;
650 bool overflow = false ;
651 bool invalid = false ;
652 unsigned int result = StrImp::toUInt( s , overflow , invalid ) ;
654 throw InvalidFormat(
"expected unsigned integer" , s ) ;
656 throw Overflow( s ) ;
660unsigned int G::StrImp::toUInt( std::string_view s ,
bool & overflow ,
bool & invalid )
noexcept
662 unsigned long ulong_val = toULong( s , overflow , invalid ) ;
663 auto result =
static_cast<unsigned int>( ulong_val ) ;
664 if( result != ulong_val )
671 bool overflow = false ;
672 bool invalid = false ;
673 unsigned long result = StrImp::toULong( s , overflow , invalid ) ;
675 throw InvalidFormat(
"expected unsigned long integer" , s ) ;
677 result = std::numeric_limits<unsigned long>::max() ;
684 return StrImp::toULongHex( s ,
true ) ;
691 return StrImp::toULongHex( s ,
false ) ;
695unsigned long G::StrImp::toULongHex( std::string_view s ,
bool limited )
697 unsigned long n = 0U ;
698 if( s.empty() )
return 0U ;
699 std::size_t i0 = s.find_first_not_of(
'0' ) ;
700 if( i0 == std::string::npos ) i0 = 0U ;
701 if( (s.size()-i0) > (
sizeof(
unsigned long)*2U) )
703 if( limited )
return ~0UL ;
704 throw Str::Overflow( s ) ;
706 for( std::size_t i = i0 ; i < s.size() ; i++ )
708 unsigned int c =
static_cast<unsigned char>(s.at(i)) ;
709 if( c >= 97U && c <= 102U ) c -= 87U ;
710 else if( c >= 65U && c <= 70U ) c -= 55U ;
711 else if( c >= 48U && c <= 57U ) c -= 48U ;
712 else throw Str::InvalidFormat(
"invalid hexadecimal" , s ) ;
721 bool overflow = false ;
722 bool invalid = false ;
723 unsigned long result = StrImp::toULong( s , overflow , invalid ) ;
725 throw InvalidFormat(
"expected unsigned long integer" , s ) ;
727 throw Overflow( s ) ;
734 return !s1.empty() && isULong(s1) ? toULong(s1) : toULong(s2) ;
738unsigned long G::StrImp::toULong( std::string_view s ,
bool & overflow ,
bool & invalid )
noexcept
746 return Str::toUnsigned<unsigned long>( s.data() , s.data()+s.size() , overflow , invalid ) ;
752 bool overflow = false ;
753 bool invalid = false ;
754 unsigned short result = StrImp::toUShort( s , overflow , invalid ) ;
756 throw InvalidFormat(
"expected unsigned short integer" , s ) ;
758 result = std::numeric_limits<unsigned short>::max() ;
766 bool overflow = false ;
767 bool invalid = false ;
768 unsigned short result = StrImp::toUShort( s , overflow , invalid ) ;
770 throw InvalidFormat(
"expected unsigned short integer" , s ) ;
772 throw Overflow( s ) ;
777unsigned short G::StrImp::toUShort( std::string_view s ,
bool & overflow ,
bool & invalid )
noexcept
779 unsigned long ulong_val = toULong( s , overflow , invalid ) ;
780 auto result =
static_cast<unsigned short>( ulong_val ) ;
781 if( result != ulong_val )
789 return StrImp::fromUnsignedToHex( u , out_p ) ;
796 return StrImp::fromUnsignedToHex( u , out_p ) ;
801std::string_view G::StrImp::fromUnsignedToHex( U u ,
char * out_p )
noexcept
804 static constexpr unsigned bytes =
sizeof(U) ;
805 static constexpr unsigned bits = 8U * bytes ;
806 static constexpr unsigned buffer_size = bytes * 2U ;
807 static const char * map =
"0123456789abcdef" ;
808 unsigned int shift = bits - 4U ;
810 for(
unsigned i = 0 ; i < (bytes*2U) ; i++ )
812 *out++ = map[(u>>shift) & 0xfUL] ;
815 std::string_view sv( out_p , buffer_size ) ;
816 return sv_substr_noexcept( sv , std::min( sv.find_first_not_of(
'0') ,
static_cast<std::size_t
>(buffer_size-1U) ) ) ;
821 std::transform( s.begin() , s.end() , s.begin() , StrImp::toLower ) ;
826 std::string out = sv_to_string( in ) ;
833 std::transform( s.begin() , s.end() , s.begin() , StrImp::toUpper ) ;
838 std::string out = sv_to_string( in ) ;
843std::string_view G::StrImp::hexmap() noexcept
845 static constexpr std::string_view chars_hexmap =
"0123456789abcdef"_sv ;
846 static_assert( chars_hexmap.size() == 16U ,
"" ) ;
847 return chars_hexmap ;
850template <
typename Tout>
851std::size_t G::StrImp::outputHex( Tout out ,
char c )
853 std::size_t n =
static_cast<unsigned char>( c ) ;
855 out( hexmap()[(n>>4U)%16U] ) ;
856 out( hexmap()[(n>>0U)%16U] ) ;
860template <
typename Tout>
861std::size_t G::StrImp::outputHex( Tout out ,
wchar_t c )
863 using uwchar_t =
typename std::make_unsigned<wchar_t>::type ;
864 std::size_t n =
static_cast<uwchar_t
>( c ) ;
866 out( hexmap()[(n>>12U)%16U] ) ;
867 out( hexmap()[(n>>8U)%16U] ) ;
868 out( hexmap()[(n>>4U)%16U] ) ;
869 out( hexmap()[(n>>0U)%16U] ) ;
873template <
typename Tout,
typename T
char>
874std::size_t G::StrImp::outputPrintable( Tout out , Tchar c , Tchar escape_in ,
char escape_out ,
bool eight_bit )
876 using Tuchar =
typename std::make_unsigned<Tchar>::type ;
877 const auto uc =
static_cast<Tuchar
>( c ) ;
885 else if( !eight_bit && uc >= 0x20U && uc < 0x7fU )
887 out(
static_cast<char>(c) ) ;
889 else if( eight_bit && ( uc >= 0x20U && uc != 0x7fU ) )
891 out(
static_cast<char>(c) ) ;
908 n += outputHex( out , c ) ;
916 result.reserve( in.length()*2U + 1U ) ;
918 StrImp::outputPrintable( [&result](
char cc){result.append(1U,cc);} , c , escape , escape , true ) ;
925 result.reserve( in.length()*2U + 1U ) ;
927 StrImp::outputPrintable( [&result](
char cc){result.append(1U,cc);} , c , escape , escape , true ) ;
934 result.reserve( in.length()*2U + 1U ) ;
936 StrImp::outputPrintable( [&result](
char cc){result.append(1U,cc);} , c , escape , escape , false ) ;
944 result.reserve( in.length()*2U + 1U ) ;
946 StrImp::outputPrintable( [&result](
wchar_t cc){result.append(1U,
static_cast<char>(cc));} , c , escape ,
static_cast<char>(escape) ,
false ) ;
954 readLine( stream , result , eol ,
false , 0U ) ;
958std::istream &
G::Str::readLine( std::istream & stream , std::string & line , std::string_view eol ,
959 bool pre_erase , std::size_t limit )
964 stream.setstate( std::ios_base::failbit ) ;
971 if( line.empty() && ( eol.empty() || eol.size() == 1U ) && limit == 0U )
973 std::getline( stream , line , eol.empty() ?
'\n' : eol[0] ) ;
977 if( eol.empty() ) eol = std::string_view(
"\n" , 1U ) ;
978 const char eol_last = eol.at( eol.size()-1U ) ;
979 const std::size_t eol_size = eol.size() ;
980 bool got_eol = StrImp::readLine( stream , line ,
nullptr , limit ? limit : line.max_size() ,
981 [eol,eol_size,eol_last](std::string &s,
char c)
984 ( c == eol_last && s.size() >= eol_size ) ?
985 s.find(eol.data(),s.size()-eol_size,eol_size) == (s.size()-eol_size) :
989 line.erase( line.size() - eol.size() ) ;
995 bool pre_erase , std::size_t limit )
997 if( eol == Eol::CrLf )
999 return readLine( stream , line ,
"\r\n"_sv , pre_erase , limit ) ;
1003 if( pre_erase && stream.good() )
1007 bool got_eol = StrImp::readLine( stream , line , &next , limit ? limit : line.max_size() ,
1008 [](std::string &,
char c)
1010 return c ==
'\n' || c ==
'\r' ;
1014 if( line.at(line.size()-1U) ==
'\r' && next ==
'\n' )
1016 line.erase( line.size()-1U ) ;
1022template <
typename T
string,
typename Fn>
1023bool G::StrImp::readLine( std::istream & stream , Tstring & line ,
char * next_p , std::size_t limit , Fn eol_fn )
1025 bool got_eol = false ;
1026 bool got_some = false ;
1027 std::istream::sentry sentry( stream ,
true ) ;
1030 using traits = std::istream::traits_type ;
1031 std::size_t count = 0U ;
1032 int c = stream.rdbuf()->sgetc() ;
1033 while( count < limit && c != traits::eof() )
1035 line.append( 1U , traits::to_char_type(c) ) ;
1036 got_eol = eol_fn( line , traits::to_char_type(c) ) ;
1041 c = stream.rdbuf()->snextc() ;
1043 got_some = count > 0U ;
1044 if( count == limit )
1046 stream.setstate( std::ios_base::failbit ) ;
1048 else if( c == traits::eof() )
1050 stream.setstate( std::ios_base::eofbit ) ;
1055 stream.rdbuf()->sbumpc() ;
1057 *next_p = traits::to_char_type( stream.rdbuf()->sgetc() ) ;
1061 stream.setstate( std::ios_base::failbit ) ;
1065template <
typename S,
typename T,
typename SV>
1066void G::StrImp::splitIntoTokens(
const S & in , T & out ,
const SV & ws )
1068 for( std::size_t p = 0U ; p != S::npos ; )
1070 p = in.find_first_not_of( ws.data() , p , ws.size() ) ;
1073 std::size_t end = in.find_first_of( ws.data() , p , ws.size() ) ;
1074 std::size_t len = end == S::npos ? end : (end-p) ;
1075 out.push_back( in.substr(p,len) ) ;
1081template <
typename S,
typename T>
1082void G::StrImp::splitIntoTokens(
const S & in , T & out ,
const S & ws ,
typename S::value_type esc )
1084 using string_type = S ;
1085 string_type ews = ws + string_type(1U,esc) ;
1086 for( std::size_t p = 0U ; p != S::npos ; )
1089 p = in.find_first_not_of( ws.data() , p , ws.size() ) ;
1090 if( p == S::npos || ( in.at(p) == esc && (p+1) == in.size() ) )
1094 std::size_t end = in.find_first_of( ews.data() , p , ews.size() ) ;
1095 while( end != S::npos && end < in.size() && in.at(end) == esc )
1096 end = (end+2) < in.size() ? in.find_first_of( ews.data() , end+2 , ews.size() ) : S::npos ;
1099 std::size_t len = end == std::string::npos ? end : (end-p) ;
1100 string_type w( in.substr(p,len) ) ;
1103 for( std::size_t i = 0 ; esc && i < w.size() ; i++ )
1107 if( (i+1) < w.size() && ws.find(w[i+1]) != S::npos )
1114 out.push_back( w ) ;
1121 if( esc && in.find(esc) != std::string::npos )
1122 StrImp::splitIntoTokens( in , out , sv_to_string(ws) , esc ) ;
1124 StrImp::splitIntoTokens( in , out , ws ) ;
1130 splitIntoTokens( in , out , ws , esc ) ;
1134template <
typename T>
1135void G::StrImp::splitIntoFields( std::string_view in , T & out , std::string_view ws )
1139 std::size_t start = 0U ;
1140 std::size_t pos = 0U ;
1143 if( pos >= in.size() ) break ;
1144 pos = in.find_first_of( ws.data() , pos , ws.size() ) ;
1145 if( pos == std::string::npos ) break ;
1146 out.push_back( sv_to_string(in.substr(start,pos-start)) ) ;
1150 out.push_back( sv_to_string(in.substr(start,pos-start)) ) ;
1154template <
typename T>
1155void G::StrImp::splitIntoFields( std::string_view in_in , T & out , std::string_view ws ,
1156 char escape ,
bool remove_escapes )
1159 ews.reserve( ws.size() + 1U ) ;
1160 ews.assign( ws.data() , ws.size() ) ;
1161 if( escape !=
'\0' ) ews.append( 1U , escape ) ;
1162 if( !in_in.empty() )
1164 std::string in = sv_to_string( in_in ) ;
1165 std::size_t start = 0U ;
1166 std::size_t pos = 0U ;
1169 if( pos >= in.size() ) break ;
1170 pos = in.find_first_of( ews , pos ) ;
1171 if( pos == std::string::npos ) break ;
1172 if( in.at(pos) == escape )
1174 if( remove_escapes )
1175 in.erase( pos , 1U ) ;
1182 out.push_back( in.substr(start,pos-start) ) ;
1187 out.push_back( in.substr(start,pos-start) ) ;
1192 char escape ,
bool remove_escapes )
1194 StrImp::splitIntoFields( in , out , std::string_view(&sep,1U) , escape , remove_escapes ) ;
1200 StrImp::splitIntoFields( in , out , std::string_view(&sep,1U) ) ;
1206 std::string_view post )
1208 std::string result ;
1210 for(
const auto & map_item : map )
1212 .append(sep.data(),(n++)?sep.size():0U)
1213 .append(map_item.first)
1214 .append(pre.data(),pre.size())
1215 .append(map_item.second)
1216 .append(post.data(),post.size()) ;
1223 std::string result ;
1225 for(
const auto & item : strings )
1227 .append(sep.data(),(n++)?sep.size():0U)
1232std::string
G::Str::join( std::string_view sep , std::string_view s1 , std::string_view s2 ,
1233 std::string_view s3 , std::string_view s4 , std::string_view s5 , std::string_view s6 ,
1234 std::string_view s7 , std::string_view s8 , std::string_view s9 )
1236 std::string result ;
1237 StrImp::join( sep , result , s1 ) ;
1238 StrImp::join( sep , result , s2 ) ;
1239 StrImp::join( sep , result , s3 ) ;
1240 StrImp::join( sep , result , s4 ) ;
1241 StrImp::join( sep , result , s5 ) ;
1242 StrImp::join( sep , result , s6 ) ;
1243 StrImp::join( sep , result , s7 ) ;
1244 StrImp::join( sep , result , s8 ) ;
1245 StrImp::join( sep , result , s9 ) ;
1249void G::StrImp::join( std::string_view sep , std::string & result , std::string_view s )
1251 if( !result.empty() && !s.empty() )
1252 result.append( sep.data() , sep.size() ) ;
1253 result.append( s.data() , s.size() ) ;
1259 result.reserve( map.size() ) ;
1260 std::transform( map.begin() , map.end() , std::back_inserter(result) ,
1261 [](
const StringMap::value_type & pair){return pair.first;} ) ;
1267 static constexpr std::string_view chars_ws =
" \t\n\r"_sv ;
1268 static_assert( chars_ws.size() == 4U ,
"" ) ;
1275 return sv_substr_noexcept( alnum_() , 0U , alnum_().size()-1U ) ;
1281 static constexpr std::string_view chars_alnum_ =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_"_sv ;
1282 static_assert( chars_alnum_.size() == 26U+10U+26U+1U ,
"" ) ;
1283 return chars_alnum_ ;
1289 static constexpr std::string_view chars_meta =
"~<>[]*$|?\\(){}\"`'&;="_sv ;
1294std::string
G::Str::head( std::string_view in , std::size_t pos , std::string_view default_ )
1297 pos == std::string::npos ?
1298 sv_to_string(default_) :
1299 ( pos == 0U ? std::string() : sv_to_string( pos >= in.size() ? in : in.substr(0U,pos) ) ) ;
1302std::string
G::Str::head( std::string_view in , std::string_view sep ,
bool default_empty )
1304 std::size_t pos = sep.empty() ? std::string::npos : in.find( sep ) ;
1305 return head( in , pos , default_empty ? std::string_view() : in ) ;
1308std::string_view
G::Str::headView( std::string_view in , std::size_t pos , std::string_view default_ )
noexcept
1311 pos == std::string::npos ?
1313 ( pos == 0U ? std::string_view(in.data(),std::size_t(0U)) : ( pos >= in.size() ? in : sv_substr_noexcept(in,0U,pos) ) ) ;
1316std::string_view
G::Str::headView( std::string_view in , std::string_view sep ,
bool default_empty )
noexcept
1318 std::size_t pos = sep.empty() ? std::string::npos : in.find( sep ) ;
1319 return headView( in , pos , default_empty ? std::string_view(in.data(),std::size_t(0U)) : in ) ;
1322std::string
G::Str::tail( std::string_view in , std::size_t pos , std::string_view default_ )
1325 pos == std::string::npos ?
1326 sv_to_string(default_) :
1327 ( (pos+1U) >= in.size() ? std::string() : sv_to_string(in.substr(pos+1U)) ) ;
1330std::string
G::Str::tail( std::string_view in , std::string_view sep ,
bool default_empty )
1332 std::size_t pos = sep.empty() ? std::string::npos : in.find(sep) ;
1333 if( pos != std::string::npos ) pos += (sep.size()-1U) ;
1334 return tail( in , pos , default_empty ? std::string_view() : in ) ;
1337std::string_view
G::Str::tailView( std::string_view in , std::size_t pos , std::string_view default_ )
noexcept
1340 pos == std::string::npos ?
1342 ( (pos+1U) >= in.size() ? std::string_view() : sv_substr_noexcept(in,pos+1U) ) ;
1345std::string_view
G::Str::tailView( std::string_view in , std::string_view sep ,
bool default_empty )
noexcept
1347 std::size_t pos = sep.empty() ? std::string::npos : in.find(sep) ;
1348 if( pos != std::string::npos ) pos += (sep.size()-1U) ;
1349 return tailView( in , pos , default_empty ? std::string_view() : in ) ;
1356 ( in.size() >= tail.size() && 0 == in.compare(in.size()-tail.size(),tail.size(),tail.data()) ) ;
1363 ( in.size() >= head.size() && 0 == in.compare(0U,head.size(),head.data()) ) ;
1378 std::string_view s = trimmedView( s_in , ws() ) ;
1379 return !s.empty() && (
1380 sv_imatch(s,
"y"_sv) || sv_imatch(s,
"yes"_sv) || sv_imatch(s,
"t"_sv) ||
1381 sv_imatch(s,
"true"_sv) || sv_imatch(s,
"1"_sv) || sv_imatch(s,
"on"_sv) ) ;
1386 std::string_view s = trimmedView( s_in , ws() ) ;
1387 return !s.empty() && (
1388 sv_imatch(s,
"n"_sv) || sv_imatch(s,
"no"_sv) || sv_imatch(s,
"f"_sv) ||
1389 sv_imatch(s,
"false"_sv) || sv_imatch(s,
"0"_sv) || sv_imatch(s,
"off"_sv) ) ;
1397bool G::StrImp::ilessc(
char c1 ,
char c2 )
noexcept
1399 if( c1 >=
'a' && c1 <=
'z' ) c1 -=
'\x20' ;
1400 if( c2 >=
'a' && c2 <=
'z' ) c2 -=
'\x20' ;
1406 return std::lexicographical_compare( a.begin() , a.end() , b.begin() , b.end() , StrImp::ilessc ) ;
1409bool G::StrImp::imatchc(
char c1 ,
char c2 )
noexcept
1411 return sv_imatch( std::string_view(&c1,1U) , std::string_view(&c2,1U) ) ;
1417 return StrImp::imatchc( c1 , c2 ) ;
1423 return sv_imatch( a , b ) ;
1427bool G::StrImp::imatch(
const std::string & a ,
const std::string & b )
1429 return sv_imatch( std::string_view(a) , std::string_view(b) ) ;
1435 return ifindat( s , key , 0U ) ;
1440 if( s.empty() || key.empty() || pos >= s.size() )
return std::string::npos ;
1441 const char * p = std::search( s.data()+pos , s.data()+s.size() , key.data() , key.data()+key.size() , StrImp::imatchc ) ;
1442 return p == (s.data()+s.size()) ? std::string::npos : std::distance(s.data(),p) ;
1445template <
typename T,
typename V>
1446T G::StrImp::unique( T in , T end , V repeat , V replacement )
1452 T in_next = in ; ++in_next ;
1453 if( *in == repeat && in_next != end && *in_next == repeat )
1455 while( in != end && *in == repeat )
1457 *out++ = replacement ;
1469 std::string s( s_in ) ;
1470 s.erase( StrImp::unique( s.begin() , s.end() , c , r ) , s.end() ) ;
1476 return s.find(c) == std::string::npos ? s : unique( s , c , c ) ;
1479void G::StrImp::strncpy(
char * dst ,
const char * src , std::size_t n )
noexcept
1482 for( ; n ; n-- , dst++ , src++ )
1490errno_t
G::Str::strncpy_s(
char * dst , std::size_t n_dst ,
const char * src , std::size_t count )
noexcept
1492 if( dst ==
nullptr || n_dst == 0U )
1495 if( src ==
nullptr )
1501 std::size_t n = std::strlen( src ) ;
1502 if( count != truncate && count < n )
1505 if( count == truncate && n >= n_dst )
1507 StrImp::strncpy( dst , src , n_dst ) ;
1508 dst[n_dst-1U] =
'\0' ;
1511 else if( n >= n_dst )
1518 StrImp::strncpy( dst , src , n ) ;
static std::string & trimRight(std::string &s, std::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 lower(std::string_view)
Returns a copy of 's' in which all seven-bit upper-case characters have been replaced by lower-case c...
static bool isUInt(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static bool isPrintable(std::string_view s) noexcept
Returns true if every character is 0x20 or above but not 0x7f.
static std::string_view trimLeftView(std::string_view, std::string_view ws, std::size_t limit=0U) noexcept
Trims the lhs of s, taking off up to 'limit' of the 'ws' characters.
static short toShort(std::string_view s)
Converts string 's' to a short.
static void splitIntoTokens(const std::string &in, StringArray &out, std::string_view ws, char esc='\0')
Splits the string into 'ws'-delimited tokens.
static std::string_view trimmedView(std::string_view s, std::string_view ws) noexcept
Returns a trim()med view of the input view.
static bool tailMatch(std::string_view in, std::string_view ending) noexcept
Returns true if the string has the given ending (or the given ending is empty).
static int toInt(std::string_view s)
Converts string 's' to an int.
static void toLower(std::string &s)
Replaces all seven-bit upper-case characters in string 's' by lower-case characters.
static void escape(std::string &s, char c_escape, std::string_view specials_in, std::string_view specials_out)
Prefixes each occurrence of one of the special-in characters with the escape character and its corres...
static std::string join(std::string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
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::string positive()
Returns a default positive string. See isPositive().
static std::string_view trimRightView(std::string_view sv, std::string_view ws, std::size_t limit=0U) noexcept
Trims the rhs of s, taking off up to 'limit' of the 'ws' characters.
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
static std::string unescaped(const std::string &s)
Returns the unescape()d version of s.
static bool isSimple(std::string_view s) noexcept
Returns true if every character is alphanumeric or "-" or "_".
static double toDouble(const std::string &s)
Converts string 's' to a double.
static std::size_t ifindat(std::string_view s, std::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 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 bool isPositive(std::string_view) noexcept
Returns true if the string has a positive meaning, such as "1", "true", "yes".
static bool headMatch(std::string_view in, std::string_view head) noexcept
Returns true if the string has the given start (or head is empty).
static std::string toPrintableAscii(const std::string &in, char escape='\\')
Returns a 7-bit printable representation of the given input string.
static std::istream & readLine(std::istream &stream, std::string &result, std::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 std::string & trim(std::string &s, std::string_view ws)
Trims both ends of s, taking off any of the 'ws' characters.
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 bool isInt(std::string_view s) noexcept
Returns true if the string can be converted into an integer without throwing an exception.
static void splitIntoFields(std::string_view in, StringArray &out, char sep, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
static std::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 std::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 void removeAll(std::string &, char)
Removes all occurrences of the character from the string. See also only().
static std::string_view alnum_() noexcept
Returns alnum() with an additional trailing underscore character.
static bool isNumeric(std::string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
static std::string negative()
Returns a default negative string. See isNegative().
static bool isUShort(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned short without throwing an exception.
static unsigned short toUShort(std::string_view s, Limited)
Converts string 's' to an unsigned short.
static bool isULong(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned long without throwing an exception.
static std::string removedAll(const std::string &, char)
Removes all occurrences of the character from the string and returns the result.
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 std::string upper(std::string_view)
Returns a copy of 's' in which all seven-bit lower-case characters have been replaced by upper-case c...
static std::size_t ifind(std::string_view s, std::string_view key)
Returns the position of the key in 's' using a seven-bit case-insensitive search.
static std::string tail(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the last part of the string after the given position.
static std::string & trimLeft(std::string &s, std::string_view ws, std::size_t limit=0U)
Trims the lhs of s, taking off up to 'limit' of the 'ws' characters.
static bool isHex(std::string_view s) noexcept
Returns true if every character is a hexadecimal digit.
static std::string readLineFrom(std::istream &stream, std::string_view eol={})
Reads a line from the stream using the given line terminator.
static void toUpper(std::string &s)
Replaces all seven-bit lower-case characters in string 's' by upper-case characters.
static std::string_view alnum() noexcept
Returns a string of seven-bit alphanumeric characters, ie A-Z, a-z and 0-9.
static std::string_view tailView(std::string_view in, std::size_t pos, std::string_view default_={}) noexcept
Like tail() but returning a view into the input string.
static unsigned int toUInt(std::string_view s)
Converts string 's' to an unsigned int.
static long toLong(std::string_view s)
Converts string 's' to a long.
static std::string fromDouble(double d)
Converts double 'd' to a string.
static unsigned int replaceAll(std::string &s, std::string_view from, std::string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
static std::string dequote(const std::string &, char qq='\"' , char esc = '\\' , std::string_view ws = Str::ws() , std::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_view ws() noexcept
Returns a string of standard whitespace characters.
static bool replace(std::string &s, std::string_view from, std::string_view to, std::size_t *pos_p=nullptr)
A std::string_view overload.
static bool match(std::string_view, std::string_view) noexcept
Returns true if the two strings are the same.
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 unsigned long toULong(std::string_view s, Limited)
Converts string 's' to an unsigned long.
static std::string_view headView(std::string_view in, std::size_t pos, std::string_view default_={}) noexcept
Like head() but returning a view into the input string.
static std::string head(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the first part of the string up to just before the given position.
static bool iless(std::string_view, std::string_view) noexcept
Returns true if the first string is lexicographically less than the first, after seven-bit lower-case...
static bool isNegative(std::string_view) noexcept
Returns true if the string has a negative meaning, such as "0", "false", "no".
static bool toBool(std::string_view s)
Converts string 's' to a bool.
static std::string_view meta() noexcept
Returns a list of shell meta-characters with a tilde as the first character.
static void unescape(std::string &s, char c_escape, std::string_view specials_in, std::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 isPrintableAscii(std::string_view s) noexcept
Returns true if every character is between 0x20 and 0x7e inclusive.
static std::string trimmed(const std::string &s, std::string_view ws)
Returns a trim()med version of s.
static std::string escaped(std::string_view, char c_escape, std::string_view specials_in, std::string_view specials_out)
Returns the escape()d string.
static std::string only(std::string_view allow_chars, std::string_view s)
Returns the 's' with all occurrences of the characters not appearing in the first string deleted.
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.