String routines to complement <string> && <cstring>:
Functions
strnum.cpp File Reference

Complement routines for <string> && <cstring> More...

#include "strnum.h"
#include <iostream>

Go to the source code of this file.

Functions

char * insnsep (char *num, char sep, unsigned w)
 Insert in place the separator 'sep' for a numeric string. More...
 
char * insnsep_Rupee (char *num, char sep)
 Use 'insnsep()' to format a Rupee amount. More...
 
char * insnsep_date8 (char *num, char sep, bool YMD)
 Use 'insnsep()' to format a date. More...
 
size_t atou_vec (const char *str, uintmax_t VEC[], size_t N)
 Takes all leading numeric values from 'str' to fill up 'VEC[]'. More...
 
size_t atoi_vec (const char *str, intmax_t VEC[], size_t N)
 Take all numeric values from 'str' to fill up 'VEC[]'. More...
 
uintmax_t atou_ndigit (const char **str, unsigned N)
 Extract the next number of 'N' digits from '*str'. More...
 
char * utoa_sz (uintmax_t val, char *dst, unsigned base, size_t sz)
 Converts 'val' into the zero terminated C-string 'dst'. More...
 

Detailed Description

Complement routines for <string> && <cstring>

Author
adolf.nosp@m.o.di.nosp@m.mare@.nosp@m.gmai.nosp@m.l.com
Date
2019

Definition in file strnum.cpp.

Function Documentation

◆ insnsep()

char* insnsep ( char *  num,
char  sep,
unsigned  w 
)

Insert in place the separator 'sep' for a numeric string.

  • The string is changed in place and its length remains the same.
  • Skips leading non numerics but handles correctly the sign '-' '+' if it inmediatly preceeds the first digit of the number.
  • Leading zeroes ('0') are treated as significant digits.
  • The space for the separators is taken from the beginning of 'num'.
  • Returns a pointer to the first digit (or sign) in the resulting string.
  • The characters to the left of the number get overwritten to make space for the separator.
  • The number in the string is extended to the left to make rooom for the separators.
  • The separator in put in place every 'w' digits, counting from the last digit.
  • To insert the comma ',' as the thousand separator use this:
    • char *first = insnsep( num, ',' ,3 );
  • On error, returns NULL and does not change 'num'. There are several error conditions:
    • When there is not enough room in the left of the string to insert the separator(s) returns NULL.
    • When ( w==0 ) returns NULL.
    • When 'num' does not have any digits to work on returns NULL.
    • When num==NULL returns NULL
  • String 'num' always remains unchanged when NULL is returned.
{{ // test::insnsep()
char *first, num[insnsep_size];
strcpy( num, ".a.=|$+12345678.00" );
/*=/=*/ first = insnsep( num, ',' , 3 );
assertTrue( 0==strcmp(first, "+12,345,678.00" ) );
assertTrue( 0==strcmp(num, ".a.=+12,345,678.00" ) );
assertTrue( 4+(3)+(8)+3 == strlen(num) );
if (first!=num) { --first; *first = '$'; } // '$' sign
assertTrue( 0==strcmp(first, "$+12,345,678.00" ) );
strcpy( num, ".|.|-12345.." ); // "$***" Example
/*=/=*/ first = insnsep( num, ',', 3 );
assertTrue( 0==strcmp(first, "-12,345.." ) );
assertTrue( 0==strcmp(num, ".|.-12,345.." ) );
if (first!=num ) { *num = '$';
while (--first!=num ) { *first='*'; }
}
assertTrue( 0==strcmp(first, "$**-12,345.." ) );
strcpy( num, " -0" ); // 0 sign
assertTrue( num+1 == (first=insnsep( num, '?' , 1 )) );
assertTrue( 0==strcmp(num," -0" ) );
strcpy( num, " +000000" ); // 0 sign
assertTrue( num == (first=insnsep( num, ',' , 3 )) );
assertTrue( 0==strcmp(num,"+000,000" ) );
assertTrue( NULL==insnsep( NULL,'|' , 1 ) ); // no string
strcpy( num, "???.xx" ); // "No Change" examples
assertTrue( NULL==insnsep( num, '|' , 1 ) ); // no digits
strcpy( num, "123.00" );
assertTrue( NULL==insnsep( num, ':' , 0 ) ); // 0==w
assertTrue( NULL==insnsep( num, '-' , 2 ) ); // No room to insert
assertTrue( 0==strcmp( num, "123.00" ) );
}}

Definition at line 42 of file strnum.cpp.

◆ insnsep_Rupee()

char* insnsep_Rupee ( char *  num,
char  sep 
)

Use 'insnsep()' to format a Rupee amount.

{{ // test::insnsep_Rupee()
char *first, num[insnsep_size];
strcpy( num , " " ); strcat(num," 32584729.25" );
first = insnsep_Rupee( num, ',' );
assertTrue( NULL!=first );
assertTrue( eqstr( num , "3,25,84,729.25" ) );
// not enough space
strcpy( num , "" ); strcat(num," 32584729.25" );
assertTrue( NULL==insnsep_Rupee( num, ',' ) );
assertTrue( eqstr( num, " 32584729.25" ) );
}}

Definition at line 98 of file strnum.cpp.

◆ insnsep_date8()

char* insnsep_date8 ( char *  num,
char  sep,
bool  YMD 
)

Use 'insnsep()' to format a date.

  • Requieres at least 8 digits to format.
  • Ignores the sign '-' '+'.
  • When 'YMD' is 'true' the first 4 digits will be assumed to be the year, otherwise the last 4 digits are the year.
    See also
    http://en.wikipedia.org/wiki/Date_format_by_country
  • Returns NULL to signal error conditions. In this case, 'num' remains unchanged.
{{ // test::insnsep_date8()
char *first, num[insnsep_size];
strcpy( num, "...**20191231.." );
/*=/=*/ first = insnsep_date8( num, '/', true );
assertTrue( eqstr(first, "2019/12/31.." ) );
assertTrue( eqstr(num, "...2019/12/31.." ) );
strcpy( num, "...**12312019.." );
/*=/=*/ first = insnsep_date8( num,'-', false );
assertTrue( eqstr(first, "12-31-2019.." ) );
assertTrue( eqstr(num, "...12-31-2019.." ) );
strcpy( num, "...**1234567.." ); // only 7 digits
assertTrue( NULL==insnsep_date8( num, '-', false ) );
assertTrue( eqstr(num, "...**1234567.." ) );
}}

Definition at line 134 of file strnum.cpp.

◆ atou_vec()

size_t atou_vec ( const char *  str,
uintmax_t  VEC[],
size_t  N 
)

Takes all leading numeric values from 'str' to fill up 'VEC[]'.

  • Ignores any dot '.' and every negative number sign '-'.
  • Numbers in 'str' should be separated by any "non digits".
  • Stores up to 'N' number in 'VEC[]'.
  • Requires 'sizeof(VEC[])<=N*sizeof(VEC[0])'.
  • Returns the number of values it stores in 'VEC[]'.
{{ // test::atou_vec()
char str[] = " 000 6 -21 \t 5 \r\n 5 5 3 3 3 2 -";
size_t RES[] = { 000,6, 21, 5, 5,5,3,3,3,2 };
uintmax_t VEC[24], dim;
assertTrue( 24 == sizeof(VEC)/sizeof(*VEC) );
assertTrue( sizeof(RES) < sizeof(VEC) );
const size_t dim_VEC = sizeof(VEC)/sizeof(*VEC);
const size_t dim_RES = sizeof(RES)/sizeof(*RES);
for ( size_t i=0; i<((dim_VEC)); ++i ) { VEC[i] = 0; }
/*=/=*/ dim = atou_vec( str,VEC, dim_VEC );
size_t i,k; {
for ( i=k=0; i<dim_RES; ++i,++k ) {
assertTrue( RES[i] == VEC[i] );
}
for ( i=k; i<((dim_VEC)); ++i ) {
assertTrue( VEC[i] == 0 );
}
assertTrue( dim == dim_RES );
}
}}

Definition at line 178 of file strnum.cpp.

◆ atoi_vec()

size_t atoi_vec ( const char *  str,
intmax_t  VEC[],
size_t  N 
)

Take all numeric values from 'str' to fill up 'VEC[]'.

  • Numbers in 'str' should be separated by any "non numerics".
  • Handles negative numbers with negative number sign '-'.
  • For negative numbers, the negative number sign '-' must immediately preceded its digits.
  • Dot '.' is ignored (no floating point).
  • Stores up to 'N' number in 'VEC[]'.
  • Requires 'sizeof(VEC[])<=N*sizeof(VEC[0])'.
  • Returns the number of values it stores in 'VEC[]'.
{{ // test::atoi_vec()
char str[] = " 000 6 -21 \t 5 \r\n 5 5 - 3 3 3 2 -";
int RES[] = { 000,6,-21, 5, 5,5, 3,3,3,2 };
intmax_t VEC[24], N;
assertTrue( 24 == sizeof(VEC)/sizeof(*VEC) );
assertTrue( sizeof(RES) < sizeof(VEC) );
const size_t dim_VEC = sizeof(VEC)/sizeof(*VEC);
const size_t dim_RES = sizeof(RES)/sizeof(*RES);
for ( size_t i=0; i<((dim_VEC)); ++i ) { VEC[i] = 0; }
/*=/=*/ N = atoi_vec( str,VEC, dim_VEC );
size_t i,k; {
for ( i=k=0; i<dim_RES; ++i,++k ) {
assertTrue( RES[i] == VEC[i] );
}
for ( i=k; i<((dim_VEC)); ++i ) {
assertTrue( VEC[i] == 0 );
}
assertTrue( N == dim_RES );
}
}}

Definition at line 214 of file strnum.cpp.

◆ atou_ndigit()

uintmax_t atou_ndigit ( const char **  str,
unsigned  N 
)

Extract the next number of 'N' digits from '*str'.

  • Skips over leading non digit characteres ['0'..'9'].
  • Only extracts consecutive digits.
  • Skips over the sign '-'.
  • Numbers in '*str' should be separated by any "non numerics".
  • If the number is too big it wont fit in a 'uintmax_t'.
  • Updates '*str' so that it points to the next character after the last digit returned.
  • Returns zero (0) if there are no further digits in '*str'.
{{ // test::atou_ndigit()
char str[128] = "IMG_20190112_151835.jpg";
unsigned long num[12];
unsigned long chk[] = { 2019,01,12,15,18,35,0 };
const char *p = str; // str == error
unsigned i=1;
num[0] = atou_ndigit( &p,4 ); // [ & ] == Ughh
assertTrue( num[0] == 2019 );
while (*p!=0) {
num[i] = atou_ndigit( &p,2 ); // & !!!
assertTrue( chk[i] == num[i] );
++i;
}
assertTrue( i==7 );
num[7] = atou_ndigit( &p,1 );
assertTrue( num[7]==0 && *p==0 );
}}

Definition at line 260 of file strnum.cpp.

◆ utoa_sz()

char* utoa_sz ( uintmax_t  val,
char *  dst,
unsigned  base,
size_t  sz 
)

Converts 'val' into the zero terminated C-string 'dst'.

  • 'dst' is converted to a 'base' numeric value.
  • 'dst' must have at least 'sz' char's (including eos=0x0).
  • Usually 'dst[] is an array where 'sz==sizeof( dst[] )'.
  • Returns a pointer to the first non zero within 'dst'.
  • Fills up with '0' the non significant digits in 'dst'.
  • [Usually does not return 'dst'].
    Precondition
    (val>=0) && (base>0) && (len>0) && 'dst' must be big enough.
    {{ // test::utoa_sz()
    char *pDst;
    { char dst5[5]; // { 1,2,3,4, 0==eos }
    pDst = utoa_sz( 101, dst5 , 10 , (( sizeof(dst5) )) );
    assertTrue( 0==strcmp( "101", pDst ) );
    assertTrue( 0==strcmp( "0101" , dst5 ) );
    }
    { char dst7[7]; // { 1,2,3,4,5,6 0==eos }
    pDst = utoa_sz( 987654321, dst7 , 10 , (( sizeof(dst7) )) );
    assertTrue( 0==strcmp( "654321", pDst ) );
    assertTrue( 0==strcmp( "654321" , dst7 ) );
    }
    { char dst32[32];
    pDst = utoa_sz( 123, dst32 , 10 , ((4+1)) );
    assertTrue( 0==strcmp( "123" , pDst) );
    assertTrue( 0==strcmp( "0123" , dst32 ) );
    pDst = utoa_sz( 11, dst32 , ((3)), ((5+1)) );
    assertTrue( 0==strcmp( "102" , pDst) );
    assertTrue( 0==strcmp( "00102" , dst32 ) );
    pDst = utoa_sz( 0*0, dst32 , 16 , ((5+1)) );
    assertTrue( 0==strcmp( "0", pDst ) );
    assertTrue( 0==strcmp( "00000", dst32 ) );
    }
    }}

Definition at line 303 of file strnum.cpp.

atou_vec
size_t atou_vec(const char *str, uintmax_t VEC[], size_t N)
Takes all leading numeric values from 'str' to fill up 'VEC[]'.
Definition: strnum.cpp:178
utoa_sz
char * utoa_sz(uintmax_t val, char *dst, unsigned base, size_t sz)
Converts 'val' into the zero terminated C-string 'dst'.
Definition: strnum.cpp:303
atoi_vec
size_t atoi_vec(const char *str, intmax_t VEC[], size_t N)
Take all numeric values from 'str' to fill up 'VEC[]'.
Definition: strnum.cpp:214
assertTrue
#define assertTrue(cond)
(cond ? () : cout << "cond" )
Definition: uUnit.h:93
insnsep_Rupee
char * insnsep_Rupee(char *num, char sep)
Use 'insnsep()' to format a Rupee amount.
Definition: strnum.cpp:98
insnsep
char * insnsep(char *num, char sep, unsigned w)
Insert in place the separator 'sep' for a numeric string.
Definition: strnum.cpp:42
insnsep_date8
char * insnsep_date8(char *num, char sep, bool YMD)
Use 'insnsep()' to format a date.
Definition: strnum.cpp:134
insnsep_size
const size_t insnsep_size
Safe size for 'insnsep()'.
Definition: strnum.h:18
eqstr
#define eqstr(a, b)
Shortcut macro to compare 2 C strings using strcmp()
Definition: strnum_test.cpp:40
atou_ndigit
uintmax_t atou_ndigit(const char **str, unsigned N)
Extract the next number of 'N' digits from '*str'.
Definition: strnum.cpp:260