25#ifndef JAU_STRING_UTIL_HPP_
26#define JAU_STRING_UTIL_HPP_
61 return 0 != std::iscntrl(c) || 0 != std::isprint(c);
64 constexpr bool is_digit(
char c)
noexcept {
return '0' <= c && c <=
'9'; }
82 std::string
trim(
const std::string &s)
noexcept;
85 std::vector<std::string>
split_string(
const std::string &str,
const std::string &separator)
noexcept;
89 std::string
toLower(
const std::string &s)
noexcept;
128 SizeBoolPair
fromHexString(std::vector<uint8_t> &out,
const uint8_t hexstr[],
const size_t hexstr_len,
196 template<
class value_type>
203#if defined(__EMSCRIPTEN__)
205 const uintptr_t v_le =
reinterpret_cast<uintptr_t
>(v);
207 byteOrder, capitalization,
prefix);
209 const uintptr_t v_le =
jau::cpu_to_le(
reinterpret_cast<uintptr_t
>(v));
211 byteOrder, capitalization,
prefix);
227 template<
class u
int8_container_type>
229 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
234 return toHexString((
const uint8_t *)bytes.data(), bytes.size(), byteOrder, capitalization, skipPrefix);
249 template<
class value_type>
259 byteOrder, capitalization,
prefix);
263 byteOrder, capitalization,
prefix);
295 SizeBoolPair
fromBitString(std::vector<uint8_t> &out,
const uint8_t bitstr[],
const size_t bitstr_len,
336 size_t bit_len=0) noexcept;
350 template<class uint8_container_type>
351 requires
jau::req::contiguous_container<uint8_container_type> &&
352 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
355 return toBitString((
const uint8_t *)bytes.data(), bytes.size(), bitOrder,
prefix, bit_len);
370 template<
class value_type>
380 bitOrder,
prefix, bit_len);
384 bitOrder,
prefix, bit_len);
402 template<
class value_type,
403 std::enable_if_t<std::is_integral_v<value_type>,
405 std::string
to_decstring(
const value_type &v,
const char separator =
',',
const nsize_t width = 0) noexcept {
408 const size_t digit10_count2 = v_sign < 0 ? digit10_count1 - 1 : digit10_count1;
410 const size_t separator_count = separator ? (digit10_count1 - 1) / 3 : 0;
411 const size_t net_chars = digit10_count1 + separator_count;
412 const size_t total_chars = std::max<size_t>(width, net_chars);
413 std::string res(total_chars,
' ');
416 size_t char_iter = 0;
418 for (
size_t digit10_iter = 0; digit10_iter < digit10_count2 ; digit10_iter++ ) {
419 const int digit = v_sign < 0 ?
invert_sign(n % 10) : n % 10;
421 if ( separator && 0 < digit10_iter && 0 == digit10_iter % 3 ) {
422 res[total_chars - 1 - (char_iter++)] = separator;
424 res[total_chars - 1 - (char_iter++)] =
'0' + digit;
427 res[total_chars - 1 - (char_iter++)] =
'-';
451 template<std::
integral value_type>
455 const nsize_t min_width = 0,
const char separator = 0,
const char padding =
'0') noexcept
457 const size_t dest_start_len = dest.size();
460 case 16: shift = 4;
break;
461 case 10: shift = 0;
break;
462 case 8: shift = 3;
break;
463 case 2: shift = 1;
break;
464 default:
return dest;
466 typedef std::make_unsigned_t<value_type> unsigned_value_type;
467 unsigned_value_type v = unsigned_value_type(
jau::abs(val) );
469 const nsize_t mask = radix - 1;
478 const nsize_t sep_gap = 10 == radix ? 3 : 4;
480 if( val_digits > 0 && separator ) {
481 if (
'0' == padding ) {
483 if ( min_width > prefix_len ) {
484 const size_t len0 = std::max<size_t>(min_width - prefix_len, val_digits);
485 sep_count = (len0 - 1) / sep_gap;
486 if ( val_digits + sep_count + prefix_len > min_width ) {
490 sep_count = (val_digits - 1) / sep_gap;
494 sep_count = (val_digits - 1) / sep_gap;
498 const size_t added_len = std::max<size_t>(min_width, val_digits + sep_count + sign_len + prefix_len);
499 dest.resize(dest_start_len + added_len,
' ');
501 const char *
const d_start = dest.data() + dest_start_len;
502 const char *
const d_start_num = d_start + prefix_len;
503 char *d = dest.data()+dest.size();
505 nsize_t digit_cnt = 0, separator_idx = 0;
506 while ( d > d_start_num ) {
507 if ( separator_idx < sep_count && 0 < digit_cnt && 0 == digit_cnt % sep_gap ) {
511 if ( d > d_start_num ) {
512 if (digit_cnt >= val_digits) {
513 if( !
sign || ( padding ==
'0' && d > d_start_num+1 ) ) {
519 }
else if ( 10 == radix ) {
520 *(--d) =
'0' + (v % 10);
523 *(--d) = hex_array[v & mask];
531 case 16: *(--d) =
'x';
break;
532 case 8: *(--d) =
'0';
break;
533 case 2: *(--d) =
'b';
break;
554 template<std::
integral value_type>
558 const nsize_t min_width = 0,
const char separator = 0,
const char padding =
'0') noexcept
565 template<
class value_type>
567 constexpr bool from_chars(value_type &result, std::string_view str)
noexcept {
571 std::string_view::const_iterator str_end = str.cend();
572 std::string_view::const_iterator begin = str.cbegin();
573 while( begin < str_end && !
jau::is_digit(*begin)) { ++begin; }
574 if( begin == str_end ) {
577 const value_type
sign = begin > str.cbegin() && *(begin-1) ==
'-' ? -1 : 1;
579 std::string_view::const_iterator end = begin + 1;
582 value_type multiplier = 1;
583 while( end > begin ) {
584 const value_type digit = *(--end) -
'0';
585 const value_type sum = digit * multiplier *
sign;
586 if(
sign > 0 && result > std::numeric_limits<value_type>::max() - sum ) {
589 }
else if(
sign < 0 && result < std::numeric_limits<value_type>::min() - sum ) {
599 template<
class value_type>
601 constexpr bool from_chars(value_type &result, std::string_view str)
noexcept {
605 std::string_view::const_iterator str_end = str.cend();
606 std::string_view::const_iterator begin = str.cbegin();
607 while( begin < str_end && !
jau::is_digit(*begin)) { ++begin; }
608 if( begin == str_end ) {
612 const value_type
sign = begin > str.cbegin() && *(begin-1) ==
'-' ? -1 : 1;
618 std::string_view::const_iterator end = begin + 1;
621 value_type multiplier = 1;
622 while( end > begin ) {
623 const value_type digit = *(--end) -
'0';
624 const value_type sum = digit * multiplier;
625 if( result > std::numeric_limits<value_type>::max() - sum ) {
657 std::string
format_string_n(
const std::size_t maxStrLen,
const char* format, ...)
noexcept;
658 std::string
vformat_string_n(
const std::size_t maxStrLen,
const char* format, va_list args)
noexcept;
673 std::string
format_string_h(
const std::size_t strLenHint,
const char* format, ...)
noexcept;
674 std::string
vformat_string_h(
const std::size_t strLenHint,
const char* format, va_list args)
noexcept;
690 void errPrint(FILE *out,
const char *msg,
bool addErrno,
bool addBacktrace,
const char *
func,
const char *file,
const int line,
691 const char* format, ...)
noexcept;
701 template<
typename CharT, std::
size_t N>
702 constexpr std::string
to_string(
const CharT (&ref)[N]) {
703 return std::string(ref);
706 template<
class value_type>
707 requires std::is_same_v<jau::StringLiteral<value_type::size>, value_type>
708 constexpr std::string
to_string(
const value_type &ref) {
709 return std::string(ref);
712 template<
class value_type,
713 std::enable_if_t<(std::is_integral_v<value_type> && !std::is_same_v<bool, std::remove_cv_t<value_type>>) ||
714 std::is_floating_point_v<value_type>,
717 return std::to_string(ref);
720 template<
class value_type,
721 std::enable_if_t<std::is_same_v<bool, std::remove_cv_t<value_type>>,
723 inline std::string
to_string(
const value_type &ref) {
724 return ref ?
"T" :
"F";
727 template<
class value_type,
728 std::enable_if_t<!std::is_integral_v<value_type> &&
729 !std::is_floating_point_v<value_type> &&
730 std::is_base_of_v<std::string, value_type>,
732 inline std::string
to_string(
const value_type &ref) {
736 template<
class value_type,
737 std::enable_if_t<!std::is_integral_v<value_type> &&
738 !std::is_floating_point_v<value_type> &&
739 !std::is_base_of_v<std::string, value_type> &&
740 std::is_base_of_v<std::string_view, value_type>,
742 inline std::string
to_string(
const value_type &ref) {
743 return std::string(ref);
746 template<
class value_type,
747 std::enable_if_t<!std::is_integral_v<value_type> &&
748 !std::is_floating_point_v<value_type> &&
749 !std::is_base_of_v<std::string, value_type> &&
750 !std::is_base_of_v<std::string_view, value_type> &&
751 std::is_same_v<char*, jau::req::base_pointer<value_type>>,
753 inline std::string
to_string(
const value_type &ref) {
754 return std::string(ref);
757 template<
class value_type,
758 std::enable_if_t<!std::is_integral_v<value_type> &&
759 !std::is_floating_point_v<value_type> &&
760 !std::is_base_of_v<std::string, value_type> &&
761 !std::is_base_of_v<std::string_view, value_type> &&
762 !std::is_same_v<char*, jau::req::base_pointer<value_type>> &&
763 std::is_pointer_v<value_type>,
765 inline std::string
to_string(
const value_type &ref) {
769 template<
class value_type,
770 std::enable_if_t<!std::is_integral_v<value_type> &&
771 !std::is_floating_point_v<value_type> &&
772 !std::is_base_of_v<std::string, value_type> &&
773 !std::is_base_of_v<std::string_view, value_type> &&
774 !std::is_pointer_v<value_type> &&
777 inline std::string
to_string(
const value_type &ref) {
778 return ref.toString();
781 template<
class value_type,
782 std::enable_if_t<!std::is_integral_v<value_type> &&
783 !std::is_floating_point_v<value_type> &&
784 !std::is_base_of_v<std::string, value_type> &&
785 !std::is_base_of_v<std::string_view, value_type> &&
786 !std::is_pointer_v<value_type> &&
790 inline std::string
to_string(
const value_type &ref) {
791 return ref.to_string();
794 template<
class value_type,
795 std::enable_if_t<!std::is_integral_v<value_type> &&
796 !std::is_floating_point_v<value_type> &&
797 !std::is_base_of_v<std::string, value_type> &&
798 !std::is_base_of_v<std::string_view, value_type> &&
799 !std::is_pointer_v<value_type> &&
804 inline std::string
to_string(
const value_type &ref) {
808 template<
class value_type,
809 std::enable_if_t<!std::is_integral_v<value_type> &&
810 !std::is_floating_point_v<value_type> &&
811 !std::is_base_of_v<std::string, value_type> &&
812 !std::is_base_of_v<std::string_view, value_type> &&
813 !std::is_pointer_v<value_type> &&
818 inline std::string
to_string(
const value_type &ref) {
824 std::string
to_string(std::vector<T>
const &list,
const std::string &delim) {
825 if ( list.empty() ) {
826 return std::string();
828 bool need_delim =
false;
830 for (
const T &e : list ) {
843 std::string
to_string(std::vector<T>
const &list,
const std::string &delim,
const nsize_t radix) {
844 if ( list.empty() ) {
845 return std::string();
847 bool need_delim =
false;
849 for (
const T &e : list ) {
879 return to_integer(str.data(), str.length(), radix, limiter, limiter_pos);
std::string toString() const noexcept
C++ Named Requirement Container (partial)
C++ Named Requirement ContiguousContainer (partial)
Concept of type-trait std::is_pointer.
Concept of type-trait std::is_signed and std::is_integral.
Concept of type-trait std::is_standard_layout.
Concept of type-trait std::is_trivially_copyable.
Concept of type-trait std::is_unsigned and std::is_integral.
constexpr bool is_little_endian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
bit_order_t
Bit order type, i.e.
constexpr uint16_t bswap(uint16_t const source) noexcept
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
constexpr uint16_t cpu_to_le(uint16_t const h) noexcept
const uint8_t * cast_char_ptr_to_uint8(const char *s) noexcept
@ msb
Identifier for most-significant-bit (msb) first.
@ big
Identifier for big endian.
@ big
Identifier for big endian, equivalent to endian::big.
constexpr bool value(const Bool rhs) noexcept
constexpr bool has_toString_v
constexpr bool has_member_of_pointer_v
constexpr bool has_to_string_v
constexpr std::enable_if_t< sizeof(Dest)==sizeof(Source) &&std::is_pointer_v< Source > &&std::is_pointer_v< Dest >, Dest > pointer_cast(const Source &src) noexcept
A constexpr pointer cast implementation for C++17, inspired by C++20 bit_cast<>(arg).
const jau::type_info & static_ctti() noexcept
Returns a static global reference of make_ctti<T>(true) w/ identity instance.
Bool
Boolean type without implicit conversion, safe for function parameter.
sint_bytes_t< sizeof(long int)> snsize_t
Natural 'ssize_t' alternative using int<XX>_t with xx = sizeof(long int)*8 as its natural sized type,...
constexpr nsize_t digits(const T x, const nsize_t radix) noexcept
Returns the number of digits of the given unsigned integral value number and the given radix.
constexpr T invert_sign(const T x) noexcept
Safely inverts the sign of an arithmetic number w/ branching in O(1)
constexpr nsize_t digits10(const T x, const snsize_t x_sign, const bool sign_is_digit=true) noexcept
Returns the number of decimal digits of the given integral value number using std::log10<T>().
constexpr int sign(const T x) noexcept
Returns the value of the sign function (w/o branching ?) in O(1).
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...
constexpr bool is_positive(const T a) noexcept
Returns true of the given integral is positive, i.e.
constexpr T abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/ branching) in O(1)
std::string & toLowerInPlace(std::string &s) noexcept
constexpr bool from_chars(value_type &result, std::string_view str) noexcept
std::string trim(const std::string &s) noexcept
trim copy
std::string & append_string(std::string &dest, value_type val, const nsize_t radix, const LoUpCase capitalization=LoUpCase::lower, const PrefixOpt prefix=PrefixOpt::prefix, const nsize_t min_width=0, const char separator=0, const char padding='0') noexcept
Appends a string representation of an integral integer value with given radix.
constexpr bool is_digit(char c) noexcept
void trimInPlace(std::string &s) noexcept
trim in place
std::string toBitString(const void *data, const nsize_t length, const bit_order_t bitOrder=bit_order_t::msb, const PrefixOpt prefix=PrefixOpt::prefix, size_t bit_len=0) noexcept
Produce a binary string representation of the given lsb-first byte values.
Int64SizeBoolTuple to_integer(const char *str, size_t str_len, const nsize_t radix=10, const char limiter='\0', const char *limiter_pos=nullptr) noexcept
Returns tuple [int64_t result, size_t consumed_chars, bool complete] of string to integer conversion ...
std::string get_string(const uint8_t *buffer, nsize_t const buffer_len, nsize_t const max_len) noexcept
Returns a C++ String taken from buffer with maximum length of min(max_len, max_len).
constexpr const char * HexadecimalArrayBig
SizeBoolPair fromBitString(std::vector< uint8_t > &out, const uint8_t bitstr[], const size_t bitstr_len, const bit_order_t bitOrder=bit_order_t::msb, const Bool checkPrefix=Bool::True) noexcept
Converts a given binary string representation into a byte vector, lsb-first.
std::vector< std::string > split_string(const std::string &str, const std::string &separator) noexcept
Split given string str at separator into the resulting std::vector excluding the separator sequence .
std::string & appendToHexString(std::string &dest, const uint8_t value, const LoUpCase capitalization=LoUpCase::lower) noexcept
Produce a hexadecimal string representation of the given byte value and appends it to the given strin...
bool is_ascii_code(int c) noexcept
std::string toLower(const std::string &s) noexcept
SizeBoolPair fromHexString(std::vector< uint8_t > &out, const uint8_t hexstr[], const size_t hexstr_len, const lb_endian_t byteOrder=lb_endian_t::big, const Bool checkPrefix=Bool::True) noexcept
Converts a given hexadecimal string representation into a byte vector, lsb-first.
constexpr const char * HexadecimalArrayLow
std::string toHexString(const void *data, const nsize_t length, const lb_endian_t byteOrder=lb_endian_t::big, const LoUpCase capitalization=LoUpCase::lower, const PrefixOpt prefix=PrefixOpt::prefix) noexcept
Produce a hexadecimal string representation of the given lsb-first byte values.
std::string to_decstring(const value_type &v, const char separator=',', const nsize_t width=0) noexcept
Produce a decimal string representation of an integral integer value.
std::string format_string_h(const std::size_t strLenHint, const char *format,...) noexcept
Returns a (non-truncated) string according to snprintf() formatting rules and variable number of argu...
std::string vformat_string_h(const std::size_t strLenHint, const char *format, va_list args) noexcept
void errPrint(FILE *out, const char *msg, bool addErrno, bool addBacktrace, const char *func, const char *file, const int line, const char *format,...) noexcept
std::string format_string_n(const std::size_t maxStrLen, const char *format,...) noexcept
Returns a (potentially truncated) string according to snprintf() formatting rules and variable number...
std::string vformat_string_n(const std::size_t maxStrLen, const char *format, va_list args) noexcept
std::string format_string(const char *format,...) noexcept
Returns a (non-truncated) string according to snprintf() formatting rules and variable number of argu...
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Simple pre-defined value tuple [int64_t, size_t, bool] for structured bindings to multi-values.
Simple pre-defined value pair [size_t, bool] for structured bindings to multi-values.
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...