    #include <ctype.h>

    #include <stdlib.h>

    #include <string.h>

    #include <stdio.h>

    #include "Strings.h"

    Strings::Strings()
    {
      theString = new char [1];
      theString [0] = '\0';
    }

    Strings::Strings (char character)
    {
      theString = new char [2];
      theString [0] = character;
      theString [1] = '\0';
    }

    Strings::Strings (const char* string)
    {
      if (string != (char*)0)
        {
        theString = new char [strlen (string) + 1];
        strcpy (theString, string);
        }
      else
        {
        theString = new char [1];
        theString [0] = '\0';
        }
    }

    Strings::Strings (const Strings& string)
    {
      theString = new char [strlen (string.theString) + 1];
      strcpy (theString, string.theString);
    }

    Strings::~Strings()
    {
      delete [] theString;
    }

    int Strings::beginsWith (const char* string) const
    {
    int result;

      if (string == (char*)0)
        result = 0;
      else
        result = !(strncmp (theString, string, strlen(string)));
      return result;
    }

    int Strings::checkMatch (char* text, char* pattern) const
    {
    // the following code was originally developed by Rich Salz.

    // the following code was modified by Lars Mathiesen.

    // the following code was modified by D J Supel

    int last, matched, reverses;
    char *t, *p;

      t = text;
      p = pattern;

      for ( ; *p; t++, p++)
      {
        if (*t == '\0' && *p != '*')
          return 0;
        switch (*p)
        {
          case '\\':
            /* Literal match with following character. */
            p++;
            /* FALLTHROUGH */
          default:
            if (*t != *p)
              return 0;
            continue;
          case '?':
            /* Match anything. */
            continue;
          case '*':
            while (*++p == '*')
              /* Consecutive stars act just like one. */
              continue;
            if (*p == '\0')
              /* Trailing star matches everything. */
              return 1;
            while (*t)
              if ((matched = checkMatch(t++, p)) != 0)
                return matched;
            return 0;
          case '[':
            reverses = p[1] == 1 ? 1 : 0;
            if (reverses)
              /* Inverted character class. */
              p++;
            for (last = 0400, matched = 0; *++p && *p != ']'; last = *p)
              if (*p == '-' ? *t <= *++p && *t >= last : *t == *p)
                matched = 1;
            if (matched == reverses)
              return 0;
            continue;
        }
      }
      return *t == '\0';
    }

    int Strings::contains (const char c) const
    {
      for (unsigned int i=0; i<=strlen (theString); i++)
      {
        if (theString[i] == c)
          return 1;
      }
      return 0;
    }

    int Strings::contains (const char* string) const
    {
      return (strstr (theString, string) != 0);
    }

    int Strings::contains (const Strings& string) const
    {
      return (strstr (theString, string.theString) != 0);
    }

    unsigned int Strings::count (const char c) const
    {
    unsigned int theCount = 0;

      for (unsigned int i=0; i<=strlen (theString); i++)
      {
        if (theString[i] == c)
          theCount++;
      }
      return theCount;
    }

    int Strings::endsWith (const char* string) const
    {
    int result;
    Strings thisString = *this;
    Strings clientString = string;

      if (string == (char*)0)
        result = 0;
      else
      {
        thisString.reverse();
        clientString.reverse();
        result = thisString.beginsWith (clientString);
      }
      return result;
    }

    int Strings::empty() const
    {
    Strings emptyString;

      return (*this == emptyString);
    }

    int Strings::isAlphabetic() const
    {
      if (empty())
        return 0;

      for (unsigned int i = 0; i<length(); i++)
      {
        if (isalpha ((int)theString[i]) || isspace ((int)theString[i]))
          ;
        else
          return 0;
      }
     return 1;
    }

    int Strings::isAlphanumeric() const
    {
      if (empty())
        return 0;

      for (unsigned int i = 0; i<length(); i++)
      {
        if (isalnum ((int)theString[i]) || isspace ((int)theString[i]))
          ;
        else
          return 0;
      }
     return 1;
    }

    int Strings::isLowercase() const
    {
      if (empty())
        return 0;

      for (unsigned int i = 0; i<length(); i++)
      {
        if (islower ((int)theString[i]) || isspace ((int)theString[i]))
          ;
        else
          return 0;
      }
     return 1;
    }

    int Strings::isNumeric() const
    {
      if (empty())
        return 0;

      for (unsigned int i = 0; i<length(); i++)
      {
        if (isdigit ((int)theString[i]))
          ;
        else
          return 0;
      }
     return 1;
    }

    int Strings::isUppercase() const
    {
      if (empty())
        return 0;

      for (unsigned int i = 0; i<length(); i++)
      {
        if (isupper ((int)theString[i]) || isspace ((int)theString[i]))
          ;
        else
          return 0;
      }
     return 1;
    }

    unsigned int Strings::length() const
    {
      return strlen (theString);
    }

    Strings Strings::lowercaseOf() const
    {
    Strings string (theString);

      string.lowercase();
      return string;
    }

    int Strings::matches (const char* pattern) const
    {
    Strings thePattern = pattern;

      return matches (thePattern);
    }

    int Strings::matches (const Strings& pattern) const
    {
      // validity check

      //

      if (pattern.empty())
        return 0;
      if (pattern.count ('[') != pattern.count (']'))
        return 0;

      if (pattern.theString[0] == '*' && pattern.theString[1] == '\0')
        return 1;
      return checkMatch (theString, pattern.theString);
    }

    int Strings::soundsLike (const char* string) const
    {
    Strings leftResult, rightResult;

      if (string == (char*)0)
        return 0;
      else
      {
        leftResult = soundexCodeOf (theString);
        rightResult = soundexCodeOf (string);
        //cerr << theString << " " << left << " "

        //     << string     << " " << right << endl;

        // determine if the soundex code could be determined by checking

        // for the empty string

        //

        if (leftResult.empty() || rightResult.empty())
          return 0;
        else
          return (leftResult == rightResult);
      }
    }

    int Strings::soundsLike (const Strings& string) const
    {
      return (soundsLike (string.theString));
    }

    double Strings::toDouble() const
    {
      return atof (theString);
    }

    int Strings::toInt() const
    {
      return atoi (theString);
    }

    long Strings::toLong() const
    {
      return atol (theString);
    }

    Strings Strings::sliceOf (const char delimitor) const
    {
    char *headMarker;
    char *tailMarker;
    Strings theToken;

      headMarker = theString;
      tailMarker = headMarker;

      while (tailMarker[0] && (tailMarker[0] != delimitor))
        tailMarker++;

      // move the token to the return strings

      //

      while (headMarker != tailMarker)
      {
        theToken.append (headMarker[0]);
        headMarker++;
      }

      return theToken;
    }

    Strings Strings::token () const
    {
    char *headMarker;
    char *tailMarker;
    Strings theToken;

      headMarker = theString;

      // skip over the preceeding spaces and set a pointer

      //

      while (headMarker[0] && isspace (headMarker[0]))
        headMarker++;

      // skip over non-blank characters and set another pointer

      //

      tailMarker = headMarker;
      while (tailMarker[0] && !isspace (tailMarker[0]))
        tailMarker++;

      // move the token to the return strings

      //

      while (headMarker != tailMarker)
      {
        theToken.append (headMarker[0]);
        headMarker++;
      }

      return theToken;
    }

    Strings Strings::token (const char delimitor) const
    {
    char *headMarker;
    char *tailMarker;
    Strings theToken;

      headMarker = theString;

      // skip over the preceeding spaces

      //

      while (headMarker[0] && isspace (headMarker[0]))
        headMarker++;

      // skip over non-delimitor characters and set another pointer

      //

      tailMarker = headMarker;
      while (tailMarker[0] && (tailMarker[0] != delimitor))
        tailMarker++;

      // move the token to the return strings

      //

      while (headMarker != tailMarker)
      {
        theToken.append (headMarker[0]);
        headMarker++;
      }

      return theToken;
    }

    Strings Strings::uppercaseOf() const
    {
    Strings string (theString);

      string.uppercase();
      return string;
    }

    void Strings::append (char character)
    {
    char *ctemp;
    char *temp;

      temp = new char [strlen (theString) + 1];
      strcpy (temp, theString);

      ctemp = new char [2];
      ctemp [0] = character;
      ctemp [1] = '\0';

      delete [] theString;
      theString = new char [strlen (temp) + strlen (ctemp) + 1];

      strcpy (theString, temp);
      strcat (theString, ctemp);

      delete [] ctemp;
      delete [] temp;
    }

    void Strings::append (const char* string)
    {
      if (string != (char*)0)
        {
        char* temp;

        temp = new char [strlen (theString) + 1];
        strcpy (temp, theString);

        delete [] theString;
        theString = new char [strlen (temp) + strlen (string) + 1];

        strcpy (theString, temp);
        strcat (theString, string);

        delete [] temp;
        }
    }

    void Strings::append (const Strings& string)
    {
    char* temp;

      temp = new char [strlen (theString) + 1];
      strcpy (temp, theString);

      if (this != &string)
      {
        delete [] theString;
        theString = new char [strlen (temp) + strlen (string.theString) + 1];

        strcpy (theString, temp);
        strcat (theString, string.theString);
      }
      else
        append (temp);

      delete [] temp;
    }

    void Strings::append (const int integer)
    {
    char number[20];

      sprintf (number, "%d", integer);
      append (number);
    }

    void Strings::clear()
    {
      delete [] theString;
      theString = new char [1];
      theString [0] = '\0';
    }

    void Strings::erase()
    {
      clear();
    }

    void Strings::lowercase()
    {
      for (unsigned int i=0; i<=strlen (theString); i++)
        theString[i] = tolower ((theString[i]));
    }

    void Strings::prepend (char character)
    {
    char *ctemp;
    char *temp;

      temp = new char [strlen (theString) + 1];
      strcpy (temp, theString);

      ctemp = new char [2];
      ctemp [0] = character;
      ctemp [1] = '\0';

      delete [] theString;
      theString = new char [strlen (temp) + strlen (ctemp) + 1];

      strcpy (theString, ctemp);
      strcat (theString, temp);

      delete [] ctemp;
      delete [] temp;
    }

    void Strings::prepend (const char* string)
    {
      if (string != (char*)0)
      {
        char* temp;

        temp = new char [strlen (theString) + 1];
        strcpy (temp, theString);

        delete [] theString;
        theString = new char [strlen (temp) + strlen (string) + 1];

        strcpy (theString, string);
        strcat (theString, temp);

        delete [] temp;
      }
    }

    void Strings::prepend (const Strings& string)
    {
    char* temp;

      temp = new char [strlen (theString) + 1];
      strcpy (temp, theString);

      if (this != &string)
      {
      delete [] theString;
      theString = new char [strlen (temp) + strlen (string.theString) + 1];

      strcpy (theString, string.theString);
      strcat (theString, temp);
      }
      else
        prepend (temp);

      delete [] temp;
    }

    void Strings::prepend (const int integer)
    {
    char number[20];

      sprintf (number, "%d", integer);
      prepend (number);
    }

    void Strings::remove (const char c)
    {
    char *newString;
    char *ptr = theString;

      newString = new char [strlen (theString) + 1];
      newString[0] = '\0';

      for (unsigned int i=0; i<(strlen(theString)); i++)
      {
        if (theString[i] != c)
          strncat (newString, ptr, 1);
        ptr++;
      }

      delete[] theString;
      theString = newString;
    }

    void Strings::replace (const char oldChar, const char newChar)
    {
      for (unsigned int i=0; i<=strlen (theString); i++)
      {
        if (theString[i] == oldChar)
          theString[i] = newChar;
      }
    }

    void Strings::replace (const char c, const char* string)
    {
    Strings result, token;

      if (contains (c)) // dont do anything if you dont have to

      {
        while (!empty())
        {
          if (contains (c))
          {
            slice (token, c, 1);
            result.append (token);
            result.append (string);
          }
          else
          {
            slice (token, c, 1);
            result.append (token);
          }
        }
        *this = result;
      }
    }

    void Strings::replace (const char c, const Strings& string)
    {
      replace (c, string.theString);
    }

    void Strings::reverse()
    {
    char c;

      for (unsigned int i=0, j=length()-1; i<length()/2; i++, j--)
      {
        c = theString[i];
        theString[i] = theString[j];
        theString[j] = c;
      }
    }

    void Strings::slice (unsigned int num, const Directions direction)
    {
      switch (direction)
      {
      case left:
        sliceLeft (num);
        break;
      case right:
        sliceRight (num);
        break;
      case leftAndRight:
        sliceLeft (num);
        sliceRight (num);
        break;
      default:
        break;
      }
    }

    void Strings::slice (
        Strings& string, const char delimitor, int removeDelimitor)
    {
      string = sliceOf (delimitor);
      sliceLeft (string.length());
      if (removeDelimitor)
         sliceLeft (1);
    }

    void Strings::sliceLeft (Strings& string, unsigned int num)
    {
    char *newString;
    unsigned int i;

      newString = new char [strlen (theString) + 1];
      strcpy (newString, theString);
      for (i=0; newString[i] && i!=num; i++)
        ;
      newString[i] = '\0';

      delete[] string.theString;
      string.theString = newString;

      sliceLeft (num);
    }

    void Strings::sliceLeft (unsigned int num)
    {
    char *marker;

      marker = theString;

      for (unsigned int i = 0; i < num; i++)
      {
        if (theString[i] == '\0')
        {
          clear();
          return;
        }
        marker++;
      }

      if (marker != theString)
      {
      char *newString;

        newString = new char [strlen (marker) + 1];
        strcpy (newString, marker);
        delete [] theString;
        theString = newString;
      }
    }

    void Strings::sliceRight (unsigned int num)
    {
    int i = 0;
    unsigned int j = 0;

       i = strlen (theString) - 1;
       if (i > 0)
         while ((i >= 0) && num != j++)
           theString[i--] = '\0';
    }

    void Strings::sliceToken (const unsigned int tokensToSlice)
    {
    Strings token;

      for (unsigned int i=0; i<tokensToSlice; i++)
        sliceToken (token);
    }

    void Strings::sliceToken (const char delimitor, int removeDelimitor)
    {
    Strings token;

      sliceToken (token, delimitor, removeDelimitor);
    }

    void Strings::sliceToken (Strings& theToken)
    {
      trimLeft();
      theToken = token();
      sliceLeft (theToken.length());
      trimLeft();
    }

    void Strings::sliceToken (
        Strings& theToken, const char delimitor, int removeDelimitor)
    {
      trimLeft();
      theToken = token (delimitor);
      sliceLeft (theToken.length());
      theToken.trimRight();
      if (removeDelimitor)
      {
         sliceLeft (1);
         trimLeft();
      }
    }

    Strings Strings::soundexCodeOf (const char* string) const
    {
    // The Soundex code is an indexing system which translates names into

    // a 4 digit code consisting of 1 letter and 3 numbers. The advantage

    // of Soundex is its ability to group names by sound rather than the

    // exact spelling.

    //

    //                              Soundex Rules

    //

    //  1. All Soundex codes have 4 alphanumeric characters [no more, no less]

    //        o 1 Letter

    //        o 3 Digits

    //  2. The Letter of the name is the first character of the Soundex code.

    //  3. The 3 digits are defined sequentially from the name using the Soundex

    //     Key below.

    //        o Adjacent letters in the name which belong to the same Soundex Key

    //          code number are assigned a single digit.

    //        o If the end of the name is reached prior to filling 3 digits, use

    //          zeroes to complete the code.

    //        o All codes have only 4 characters, even if the name is long enough

    //          to yield more.

    //

    int value, previous;
    Strings code;

      // error checking for null pointers and strings of length zero

      //

      if (string == (char*)0)
        return code;
      if (!isalpha (string[0]))
        return code;

      code.append (string[0]);
      code.uppercase();

      value = 0;
      for (unsigned int i = 1; string[i]!= '\0' && (code.length() < 4); i++)
      {
        previous = value;
        value = soundexNumericOf (string[i]);
        if ((value != 0) && (value != previous))
          code.append (value);
      }

      while (code.length() < 4)
       code.append ('0');

      return code;
    }

    int Strings::soundexNumericOf (const char c) const
    {
    // The Soundex Key

    //

    //   1           B P F V

    //   2       C S K G J Q X Z

    //   3             D T

    //   4              L

    //   5             M N

    //   6              R

    //   no code  A E H I O U Y W

    //

    int result = 0;
    char temp = toupper (c);

      switch (temp)
      {
      case 'B':
      case 'P':
      case 'F':
      case 'V':
        result = 1;
        break;
      case 'C':
      case 'S':
      case 'K':
      case 'G':
      case 'J':
      case 'Q':
      case 'X':
      case 'Z':
        result = 2;
        break;
      case 'D':
      case 'T':
        result = 3;
        break;
      case 'L':
        result = 4;
        break;
      case 'M':
      case 'N':
        result = 5;
        break;
      case 'R':
        result = 6;
        break;
      default:
        break;
      }
      return result;
    }

    void Strings::swap (Strings& string)
    {
    Strings temp;

      temp = *this;
      *this = string;
      string = temp;
    }

    void Strings::trim (const Directions direction)
    {
      switch (direction)
      {
      case left:
        trimLeft();
        break;
      case right:
        trimRight();
        break;
      case leftAndRight:
        trimLeft();
        trimRight();
        break;
      default:
        break;
      }
    }

    void Strings::trimLeft()
    {
    char *marker;

      marker = theString;

      while (isspace (marker[0]))
        marker++;

      if (marker != theString)
      {
      char *newString;

        newString = new char [strlen (marker) + 1];
        strcpy (newString, marker);
        delete [] theString;
        theString = newString;
      }
    }

    void Strings::trimRight()
    {
    int i;

       i = strlen (theString) - 1;
       if (i > 0)
         while ((i >= 0) && isspace (theString[i]))
           theString[i--] = '\0';
    }

    void Strings::trim (const char c, const Directions direction)
    {
      switch (direction)
      {
      case left:
        trimLeft (c);
        break;
      case right:
        trimRight (c);
        break;
      case leftAndRight:
        trimLeft (c);
        trimRight (c);
        break;
      default:
        break;
      }
    }

    void Strings::trimLeft (const char c)
    {
    char *marker;

      marker = theString;

      while (c == marker[0])
        marker++;

      if (marker != theString)
      {
      char *newString;

        newString = new char [strlen (marker) + 1];
        strcpy (newString, marker);
        delete [] theString;
        theString = newString;
      }
    }

    void Strings::trimRight (const char c)
    {
    int i;

       i = strlen (theString) - 1;
       if (i > 0)
         while ((i >= 0) && c == theString[i])
           theString[i--] = '\0';
    }

    void Strings::uppercase()
    {
      for (unsigned int i=0; i<=strlen (theString); i++)
        theString[i] = toupper (theString[i]);
    }

    Strings::operator const char*() const
    {
      return theString;
    }

    ostream& operator << (ostream& outputStream, const Strings&  string)
    {
      return outputStream << string.theString;
    }

    const Strings& Strings::operator = (char character)
    {
      delete [] theString;
      theString = new char [2];
      theString [0] = character;
      theString [1] = '\0';
      return *this;
    }

    const Strings& Strings::operator = (const char* string)
    {
      delete [] theString;
      if (string != (char*)0)
        {
        theString = new char [strlen (string) + 1];
        strcpy (theString, string);
        }
      else
        {
        theString = new char [1];
        theString [0] = '\0';
        }
      return *this;
    }

    const Strings& Strings::operator = (const Strings& string)
    {
      if (this != &string)
      {
        delete [] theString;
        theString = new char [strlen (string.theString) + 1];
        strcpy (theString, string.theString);
      }
      return *this;
    }

    Strings operator + (const Strings& string1, const Strings& string2)
    {
    Strings temp;

      temp = string1;
      temp.append (string2);
      return temp;
    }

    Strings operator + (const Strings& string, const char* s)
    {
    Strings temp;

      temp = string;
      temp.append (s);
      return temp;
    }

    Strings operator + (const char* s, const Strings& string)
    {
    Strings temp;

      temp = s;
      temp.append (string);
      return temp;
    }

    Strings operator + (const Strings& string, const char character)
    {
    Strings temp;

      temp = string;
      temp.append (character);
      return temp;
    }

    Strings operator + (const char character, const Strings& string)
    {
    Strings temp;

      temp = character;
      temp.append (string);
      return temp;
    }

    Strings operator + (const Strings& string, const int number)
    {
    Strings temp;

      temp = string;
      temp.append (number);
      return temp;
    }

    Strings operator + (const int number, const Strings& string)
    {
    Strings temp;

      temp.append (number);
      temp.append (string);
      return temp;
    }

    const Strings& Strings::operator += (char character)
    {
      append (character);
      return *this;
    }

    const Strings& Strings::operator += (const char* string)
    {
      append (string);
      return *this;
    }

    const Strings& Strings::operator += (const Strings& string)
    {
      append (string);
      return *this;
    }

    const Strings& Strings::operator += (const int number)
    {
      append (number);
      return *this;
    }

    int Strings::operator == (const Strings& string) const
    {
      return (strcmp (theString, string.theString) == 0);
    }

    int Strings::operator == (const char* string) const
    {
      return (strcmp (theString, string) == 0);
    }

    int Strings::operator != (const Strings& string) const
    {
      return !(strcmp (theString, string.theString) == 0);
    }

    int Strings::operator != (const char* string) const
    {
      return !(strcmp (theString, string) == 0);
    }

    int Strings::operator < (const Strings& string) const
    {
      return (strcmp (theString, string.theString) < 0);
    }

    int Strings::operator < (const char* string) const
    {
      return (strcmp (theString, string) < 0);
    }

    int Strings::operator > (const Strings& string) const
    {
      return (strcmp (theString, string.theString) > 0);
    }

    int Strings::operator > (const char* string) const
    {
      return (strcmp (theString, string) > 0);
    }

    int Strings::operator <= (const Strings& string) const
    {
      return (strcmp (theString, string.theString) <= 0);
    }

    int Strings::operator <= (const char* string) const
    {
      return (strcmp (theString, string) <= 0);
    }

    int Strings::operator >= (const Strings& string) const
    {
      return (strcmp (theString, string.theString) >= 0);
    }

    int Strings::operator >= (const char* string) const
    {
      return (strcmp (theString, string) >= 0);
    }

    const char& Strings::operator [] (const unsigned int index) const
    {
      if (index > length())
        return theString[length()];
      else
        return theString[index];
    }

    // Copyright (c) 1995-1997 D J Supel and ISX Corporation

syntax highlighted by Code2HTML, v. 0.9.1