#include #include #include #include std :: vector split ( const std :: string & str , const std :: string & delim ) { std :: vector strings ; size_t start ; size_t end = 0 ; while ( ( start = str . find_first_not_of ( delim , end ) ) != std :: string :: npos ) { end = str . find ( delim , start ) ; strings . push_back ( str . substr ( start , end - start ) ) ; } return strings ; } std :: uint32_t utf8_encode ( char * out , uint32_t utf ) { if ( utf > 6 ) & 0x1F ) | 0xC0 ) ; out [ 1 ] = ( char ) ( ( ( utf >> 0 ) & 0x3F ) | 0x80 ) ; out [ 2 ] = 0 ; return 2 ; } else if ( utf > 12 ) & 0x0F ) | 0xE0 ) ; out [ 1 ] = ( char ) ( ( ( utf >> 6 ) & 0x3F ) | 0x80 ) ; out [ 2 ] = ( char ) ( ( ( utf >> 0 ) & 0x3F ) | 0x80 ) ; out [ 3 ] = 0 ; return 3 ; } else if ( utf > 18 ) & 0x07 ) | 0xF0 ) ; out [ 1 ] = ( char ) ( ( ( utf >> 12 ) & 0x3F ) | 0x80 ) ; out [ 2 ] = ( char ) ( ( ( utf >> 6 ) & 0x3F ) | 0x80 ) ; out [ 3 ] = ( char ) ( ( ( utf >> 0 ) & 0x3F ) | 0x80 ) ; out [ 4 ] = 0 ; return 4 ; } else { // error - use replacement character out [ 0 ] = ( char ) 0xEF ; out [ 1 ] = ( char ) 0xBF ; out [ 2 ] = ( char ) 0xBD ; out [ 3 ] = 0 ; return 0 ; } } std :: string cp_to_utf8 ( const std :: string & input ) { std :: string out ; std :: regex re ( R"((?:(?:\\\\)|(?:\\[uU](?:[0-9a-fA-F]{8}|[0-9a-fA-F]{4})))|(?:.))" ) ; std :: regex_token_iterator it ( input . cbegin ( ) , input . cend ( ) , re ) ; decltype ( it ) end ; for ( ; it != end ; ++ it ) { auto ms = it -> str ( ) ; if ( ms . rfind ( "\\u" ) == 0 || ms . rfind ( "\\U" ) == 0 ) { auto s = ms . substr ( 2 ) ; unsigned int value ; auto [ ptr , err ] = std :: from_chars ( s . c_str ( ) , s . c_str ( ) + s . size ( ) , value , 16 ) ; if ( err == std :: errc ( ) ) { char buf [ 8 ] ; auto len = utf8_encode ( buf , value ) ; if ( ! len ) { throw std :: invalid_argument { "Invalid unicode codepoint 0x" s + hex } ; } out . append ( std :: string { buf , len } ) ; } else if ( err == std :: errc :: invalid_argument ) { throw std :: invalid_argument { s } ; } else if ( err == std :: errc :: result_out_of_range ) { throw std :: out_of_range { s } ; } } else { out . append ( ms ) ; } } return out ; }