Using the charstring class


Introduction

The charstring class provides static methods for manipulating C-style character strings.

In addition to some unique methods, analogs for the standard C string functions are provided. However, unlike the standard C string functions, the charstring methods are NULL safe. Your application will not crash if a NULL is passed in, and instead, will give intuitive results.


Manipulating Character Strings

The charstring class provides methods for zeroing, duplicating, appending, copying data to, printing formatted data to, and determining the lengths of character strings.

#include <rudiments/charstring.h>
#include <rudiments/stdio.h>

int main(int argc, const char **argv) {

        char            buffer[32];


        // zero the buffer
        charstring::zero(buffer,sizeof(buffer));


        // append strings, integers and floats
        charstring::append(buffer,"Hello ");
        charstring::append(buffer,"there!",6);
        charstring::append(buffer," ");
        charstring::append(buffer,(uint64_t)1);
        charstring::append(buffer,(uint64_t)2);
        charstring::append(buffer,(uint64_t)3);
        charstring::append(buffer," ");
        charstring::append(buffer,1.234,4,3);
        stdoutput.printf("buffer: %s\n",buffer);
        stdoutput.write('\n');


        // get length
        stdoutput.printf("length(buffer)=%d\n",charstring::length(buffer));
        stdoutput.write('\n');


        // zero the buffer again
        charstring::zero(buffer,sizeof(buffer));


        // copy to the beginning of the buffer
        charstring::copy(buffer,"Hello!");
        stdoutput.printf("buffer: %s\n",buffer);


        // copy the specified number of bytes to the beginning of the buffer
        charstring::copy(buffer,"Hello again!",6);
        stdoutput.printf("buffer: %s\n",buffer);


        // copy to the specified offset
        charstring::copy(buffer,6,"again!");
        stdoutput.printf("buffer: %s\n",buffer);


        // copy the specified number of bytes to the specified offset
        charstring::copy(buffer,12," Hi!  blah blah blah",4);
        stdoutput.printf("buffer: %s\n",buffer);
        stdoutput.write('\n');


        // get length
        stdoutput.printf("length(buffer)=%d\n",charstring::length(buffer));
        stdoutput.write('\n');


        // zero the buffer again
        charstring::zero(buffer,sizeof(buffer));


        // safely copy a long string to a smaller buffer
        charstring::safeCopy(buffer,sizeof(buffer),
                                "This string is longer than the buffer");
        stdoutput.printf("buffer: %.*s\n",sizeof(buffer),buffer);


        // safely copy the specified number of bytes of a
        // long string to a smaller buffer
        charstring::safeCopy(buffer,sizeof(buffer),
                                "This string is longer than the buffer",36);
        stdoutput.printf("buffer: %.*s\n",sizeof(buffer),buffer);
        stdoutput.write('\n');


        // get length
        stdoutput.printf("length(buffer)=%d\n",charstring::length(buffer));
        stdoutput.write('\n');


        // zero the buffer again
        charstring::zero(buffer,sizeof(buffer));


        // print formatted data to the buffer
        charstring::printf(buffer,sizeof(buffer),"%s%05d%7.4f",
                                                "hello",100,123.4567);
        stdoutput.printf("buffer: %s\n",buffer);
        stdoutput.write('\n');


        // get length
        stdoutput.printf("length(buffer)=%d\n",charstring::length(buffer));
        stdoutput.write('\n');


        // duplicate a string
        char    *completedup=charstring::duplicate("Hello there!");
        char    *partialdup=charstring::duplicate("Hello there!",5);
        stdoutput.printf("complete duplicate of \"Hello there!\"\"%s\"\n",
                                                                completedup);
        stdoutput.printf(" partial duplicate of \"Hello there!\"\"%s\"\n",
                                                                partialdup);
        delete[] completedup;
        delete[] partialdup;
}

Comparing Character Strings

The charstring class also provides methods for performing various character string comparisons.

#include <rudiments/charstring.h>
#include <rudiments/stdio.h>

int main(int argc, const char **argv) {

        // comparing string...
        const char * const strings[]={
                "hello","HELLO","hello there","HELLO THERE",NULL
        };

        stdoutput.write("direct comparison...\n");
        for (const char * const *s=strings; *s; s++) {
                stdoutput.printf("  does \"hello\"=\"%s\"  %s?\n",*s,
                        (!charstring::compare("hello",*s))?"yes":"no");
                
        }
        stdoutput.write('\n');

        stdoutput.write("only first 5 bytes...\n");
        for (const char * const *s=strings; *s; s++) {
                stdoutput.printf("  does \"hello\"=\"%s\"?  %s\n",*s,
                        (!charstring::compare("hello",*s,5))?"yes":"no");
        }
        stdoutput.write('\n');

        stdoutput.write("ignoring case...\n");
        for (const char * const *s=strings; *s; s++) {
                stdoutput.printf("  does \"hello\"=\"%s\"?  %s\n",*s,
                        (!charstring::compareIgnoringCase("hello",*s,5))?
                                                                "yes":"no");
        }
        stdoutput.write('\n');

        stdoutput.write("ignoring case, only first 5 bytes...\n");
        for (const char * const *s=strings; *s; s++) {
                stdoutput.printf("  does \"hello\"=\"%s\"?  %s\n",*s,
                        (!charstring::compareIgnoringCase("hello",*s,5))?
                                                                "yes":"no");
        }
        stdoutput.write('\n');



        // member of a set...
        const char * const greetings[]={
                "hello","hi","good morning",NULL
        };
        const char * const lowercaseexpressions[]={
                "hello","hi","bye","goodbye",NULL
        };
        const char * const uppercaseexpressions[]={
                "HELLO","HI","BYE","GOODBYE",NULL
        };

        stdoutput.write("considering case...\n");
        for (const char * const *le=lowercaseexpressions; *le; le++) {
                stdoutput.printf("  is \"%s\" a greeting?  %s\n",*le,
                        (charstring::inSet(*le,greetings))?"yes":"no");
        }
        stdoutput.write('\n');

        stdoutput.write("ignoring case...\n");
        for (const char * const *ue=uppercaseexpressions; *ue; ue++) {
                stdoutput.printf("  is \"%s\" a greeting?  %s\n",*ue,
                        (charstring::inSetIgnoringCase(*ue,greetings))?
                                                                "yes":"no");
        }
        stdoutput.write('\n');


        // does one string contain another?
        const char      phrase[]="the quick brown fox jumped over the lazy dog";
        const char * const lowercasewords[]={
                "quick","brown","fox","lazy","dog","hello","goodbye",NULL
        };
        const char * const uppercasewords[]={
                "QUICK","BROWN","FOX","LAZY","DOG","HELLO","GOODBYE",NULL
        };
        
        stdoutput.write("considering case...\n");
        for (const char * const *lw=lowercasewords; *lw; lw++) {
                stdoutput.printf("  does \"%s\" contain \"%s\"?  %s\n",
                        phrase,*lw,
                        (charstring::contains(phrase,*lw))?"yes":"no");
        }
        stdoutput.write('\n');
        
        stdoutput.write("ignoring case...\n");
        for (const char * const *uw=uppercasewords; *uw; uw++) {
                stdoutput.printf("  does \"%s\" contain \"%s\"?  %s\n",
                        phrase,*uw,
                        (charstring::contains(phrase,*uw))?"yes":"no");
        }
        stdoutput.write('\n');
}

Finding Data in Character Strings

The charstring class also provides methods for finding characters or other character strings within character strings.

The findFirst()/findFirstOfSet() and findLast() methods return the first/last instance of a character/string/set within a string, or NULL if no match is found.

#include <rudiments/charstring.h>
#include <rudiments/stdio.h>

int main(int argc, const char **argv) {

        // first/last instances of a character or string...
        const char      phrase[]="1 and 2 and 3 and 4";
        const char      numbers[]="1234";

        const char      *firsta=charstring::findFirst(phrase,'a');
        const char      *firstand=charstring::findFirst(phrase,"and");

        const char      *lasta=charstring::findLast(phrase,'a');
        const char      *lastand=charstring::findLast(phrase,"and");

        const char      *firstnum=charstring::findFirstOfSet(phrase,numbers);

        stdoutput.printf("in the phrase: \"%s\"...\n",phrase);
        stdoutput.printf("  the first 'a' is    : \"%s\"\n",firsta);
        stdoutput.printf("  the first \"and\" is        : \"%s\"\n",firstand);
        stdoutput.printf("  the last 'a' is     : \"%s\"\n",lasta);
        stdoutput.printf("  the last \"and\" is : \"%s\"\n",lastand);
        stdoutput.printf("  the first number is : \"%s\"\n",firstnum);
        stdoutput.write('\n');
}

Transforming Character Strings

The charstring class also provides methods for transforming character strings.

#include <rudiments/charstring.h>
#include <rudiments/stdio.h>

int main(int argc, const char **argv) {

        char    hellothere[]="   hello there!   ";

        // upper-case...
        charstring::upper(hellothere);
        stdoutput.printf("upper cased:   \"%s\"\n",hellothere);

        // lower-case...
        charstring::lower(hellothere);
        stdoutput.printf("lower cased:   \"%s\"\n",hellothere);

        // capitalized...
        charstring::capitalize(hellothere);
        stdoutput.printf("capitalized:   \"%s\"\n",hellothere);

        // right trimmed...
        charstring::rightTrim(hellothere);
        stdoutput.printf("right trimmed: \"%s\"\n",hellothere);

        // left trimmed...
        charstring::leftTrim(hellothere);
        stdoutput.printf("left trimmed:  \"%s\"\n",hellothere);
        stdoutput.write('\n');



        char    paragraph[]="Hello there.\n This is a paragraph\n "
                                "with random\n carriage returns\n "
                                "scattered throughout.";

        // original...
        stdoutput.printf("original text:\n%s\n\n",paragraph);

        // stripped of carraige returns...
        charstring::strip(paragraph,'\n');
        stdoutput.printf("text without carriage returns:\n%s\n\n",paragraph);

        // stripped of "Hello there."...
        charstring::strip(paragraph,"Hello there. ");
        stdoutput.printf("text without \"Hello There. \":\n%s\n\n",paragraph);

        // with replacements...
        charstring::replace(paragraph,' ','_');
        stdoutput.printf("text with spaces replaced by underscores:\n%s\n\n",
                                                                paragraph);



        char    paddedtext[]="   hello   ";

        // original...
        stdoutput.printf("original text:   \"%s\"\n",paddedtext);

        // left-justified...
        charstring::leftJustify(paddedtext,charstring::length(paddedtext));
        stdoutput.printf("left-justified:  \"%s\"\n",paddedtext);

        // right-justified...
        charstring::rightJustify(paddedtext,charstring::length(paddedtext));
        stdoutput.printf("right-justified: \"%s\"\n",paddedtext);

        // centered...
        charstring::center(paddedtext,charstring::length(paddedtext));
        stdoutput.printf("centered:        \"%s\"\n",paddedtext);
        stdoutput.write('\n');



        const char      unpaddedtext[]="hellothere";

        // original...
        stdoutput.printf("original text:      \"%s\"\n",unpaddedtext);

        // left-padded
        char    *leftpadded=charstring::pad(unpaddedtext,' ',-1,15);
        stdoutput.printf("left padded text:   \"%s\"\n",leftpadded);
        delete[] leftpadded;

        // right-padded
        char    *rightpadded=charstring::pad(unpaddedtext,' ',1,15);
        stdoutput.printf("right padded text:  \"%s\"\n",rightpadded);
        delete[] rightpadded;

        // center-padded
        char    *centerpadded=charstring::pad(unpaddedtext,' ',0,15);
        stdoutput.printf("center padded text: \"%s\"\n",centerpadded);
        delete[] centerpadded;
}

Parsing Character Strings

The charstring class also provides methods for splitting character strings, finding substrings and inserting text into a character string.

#include <rudiments/charstring.h>
#include <rudiments/stdio.h>

int main(int argc, const char **argv) {

        const char      str[]="All along the untrodden paths of the future...";

        // split...
        char            **parts;
        uint64_t        partcount;
        charstring::split(str," ",true,&parts,&partcount);

        stdoutput.printf("original string:\n  %s\n",str);
        stdoutput.printf("split on space:\n");
        for (uint64_t i=0; i<partcount; i++) {
                stdoutput.printf("  %s\n",parts[i]);
        }
        stdoutput.write('\n');

        for (uint64_t i=0; i<partcount; i++) {
                delete[] parts[i];
        }
        delete[] parts;



        // substring...
        char    *substring1=charstring::subString(str,14);
        char    *substring2=charstring::subString(str,14,28);

        stdoutput.printf("string starting at index 14: %s\n",substring1);
        stdoutput.printf("string from index 14 to 21 : %s\n",substring2);
        stdoutput.write('\n');

        delete[] substring1;
        delete[] substring2;



        // insert string...
        char    *newstr=charstring::insertString(str,
                        ", I can see the footprints of an unseen hand",43);

        stdoutput.printf("string after insert:\n  %s\n",newstr);
        stdoutput.write('\n');

        delete[] newstr;
}

Converting Numbers and Amounts

The charstring class also provides methods for converting numbers and dollar amounts to and from character strings.

#include <rudiments/charstring.h>
#include <rudiments/stdio.h>

int main(int argc, const char **argv) {

        // conversion of numbers to strings...
        char    *intstr=charstring::parseNumber((uint64_t)12345);
        char    *floatstr=charstring::parseNumber((float)12.345,5,3);

        stdoutput.printf("numbers as strings: %s%s\n",intstr,floatstr);
        stdoutput.write('\n');

        delete[] intstr;
        delete[] floatstr;



        // conversion of strings to numbers...
        int64_t         intnum=charstring::toInteger("12345");
        uint64_t        uintnum=charstring::toUnsignedInteger("12345");
        long double     floatnum=charstring::toFloat("12.345");

        stdoutput.printf("strings as numbers: %lld%lld%5.3Lf\n",
                                                intnum,uintnum,floatnum);
        stdoutput.write('\n');



        // identification of numeric strings...
        const char * const numbers[]={
                "1","-1","1.1","-1.1","one","hello",NULL
        };
        
        for (const char * const *n=numbers; *n; n++) {
                stdoutput.printf("%s %s a number\n",*n,
                                (charstring::isNumber(*n))?"is":"is not");
                stdoutput.printf("%s %s an integer\n",*n,
                                (charstring::isInteger(*n))?"is":"is not");
        }
        stdoutput.write('\n');



        // integer lengths
        uint64_t        integers[]={
                1,23,456,7890,12345,678901,0
        };

        for (uint64_t *i=integers; *i; i++) {
                stdoutput.printf("it would take %d bytes to store "
                                        "%lld as a string\n",
                                        charstring::integerLength(*i),*i);
        }
        stdoutput.write('\n');



        // dollar amounts
        const char      dollarstr[]="$123.45";
        int64_t pennies=charstring::convertAmount(dollarstr);
        char    *dollars=charstring::convertAmount(pennies);
        stdoutput.printf("%s as pennies: %lld\n",dollarstr,pennies);
        stdoutput.printf("%lld pennies as dollars: %s\n",pennies,dollars);
}

Encoding Character Strings

The charstring class also provides methods for escaping, encoding and obfuscating character strings.

#include <rudiments/charstring.h>
#include <rudiments/stdio.h>

int main(int argc, const char **argv) {

        // http escape...
        const char      httpstr[]="string with spaces and symbols: \\{}\"\'";

        stdoutput.printf("original string:\n  %s\n",httpstr);

        char    *escapedstr=charstring::httpEscape(httpstr);
        stdoutput.printf("http escaped string:\n  %s\n",escapedstr);

        char    *unescapedstr=charstring::httpUnescape(escapedstr);
        stdoutput.printf("http unescaped string:\n  %s\n",unescapedstr);
        stdoutput.write('\n');

        delete[] escapedstr;
        delete[] unescapedstr;



        // backslash-escaping of quote, backslash and space characters...
        const char      path[]="\"C:\\Program Files\\Firstworks\"";

        stdoutput.printf("original path:\n  %s\n",path);

        char    *escapedpath=charstring::escape(path,"\"\\ ");
        stdoutput.printf("escaped path:\n  %s\n",escapedpath);

        char    *unescapedpath=charstring::unescape(escapedpath);
        stdoutput.printf("unescaped path:\n  %s\n",unescapedpath);
        stdoutput.write('\n');

        delete[] escapedpath;
        delete[] unescapedpath;



        // base-64 encoding...
        const unsigned char     text[]="All along the untrodden "
                                        "paths of the future...";

        stdoutput.printf("original text:\n  %s\n",text);

        char    *encodedtext=charstring::base64Encode(text);
        stdoutput.printf("encoded text:\n  %s\n",encodedtext);

        unsigned char   *decodedtext=charstring::base64Decode(encodedtext);
        stdoutput.printf("decoded text:\n  %s\n",decodedtext);
        stdoutput.write('\n');

        delete[] encodedtext;
        delete[] decodedtext;



        // obfuscation...
        char    data[]="sensitive data";

        stdoutput.printf("original data:\n  %s\n",data);

        charstring::obfuscate(data);
        stdoutput.write("obfuscated data:\n  ");
        stdoutput.safePrint(data);
        stdoutput.write("\n");

        charstring::deobfuscate(data);
        stdoutput.printf("deobfuscated data:\n  %s\n",data);
}