Author Topic: ProgEx33 -- C++ Version Of String::Parse And String::ParseCount  (Read 5864 times)

0 Members and 1 Guest are viewing this topic.

Offline Frederick J. Harris

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 938
    • Frederick J. Harris
ProgEx33 -- C++ Version Of String::Parse And String::ParseCount
« on: November 26, 2009, 05:19:57 AM »
Code: [Select]
/*
  ProgEx33 -- C++ Version Of String::Parse
  
  I remember being really thrilled when I discovered PowerBASIC's ParseCount -
  Parse combination.  Its language elements like that that really help applic-
  ation programmers get things done.  And that is the sort of language element
  which C always lacked - C's strtok() function notwithstanding.  So when I
  built my C++ String Class its something I wanted to include for sure.  Before
  looking at a C++ String Class implementation, lets first look at how Parse
  works in PowerBASIC so we're all on the same page. Lets imagine we have my
  name to Parse with my first, middle and last names separated by commas...
  
  'First PowerBASIC Version
  #Compile Exe
  #Dim All

  Function PBMain() As Long
    Local strArr() As String
    Local strName As String
    Register i As Long
  
    strName="Frederick, John, Harris"
    Redim strArr(ParseCount(strName,",")-1)
    Parse strName, strArr(), ","
    Print " i            strArr(i)"
    Print "========================"
    For i=0 To UBound(strArr,1)
      Print i, LTrim$(strArr(i))
    Next i
    Erase strArr()
    Waitkey$

    PBMain=0
  End Function

  ' i            strArr(i)
  '========================
  ' 0            Frederick
  ' 1            John
  ' 2            Harris
  
  
  //Then C++ Version With My String Class
  #include <stdio.h>
  #include "Strings.h"

  int main(void)
  {
   String s1("Frederick, John, Harris");
   unsigned int iCount;
   String* pStr=NULL;  
 
   iCount=s1.ParseCount(',');
   pStr=new String[iCount];
   s1.Parse(pStr,',');
   printf("&pStr[i]\tpStr[i].lpStr()\t\tpStr[i].lpStr()\n");
   printf("=======================================================\n");
   for(unsigned int i=0; i<iCount; i++)
   {
       pStr[i].LTrim();
       printf("%u\t\t%u\t\t\t%s\n",(unsigned int)&pStr[i],(unsigned int)pStr[i].lpStr(),pStr[i].lpStr());
   }    
   delete [] pStr;
   getchar();  
    
   return 0;  
  }

  The PowerBASIC version comes out to 21 lines and the C++ version to 24.  
  The comparison is certainly interesting though.  The above C++ code isn't
  exactly like the compilable version below because in that version I put all
  the processing code in a procedure named DoProcessing() so that the
  destructors for all the various Strings would get called and print diagnostic
  output statements for your examination.  As I mentioned several Program
  Examples back, destructors for Strings created in main() are sometimes not
  called until after the console has been closed and main() has exited.  I
  wanted to avoid that.
  
  In the past several String Class Program Examples I've only added a new
  feature or two in each new example.  At that rate it will take me forever to
  get through all this.  So in this ProgEx I'm going to just provide my whole
  Ansi version of my String Class as it now stands.  However, I'll provide some
  derivation information on the development of Parse because its so useful. The
  other members that emulate BASIC String functions such as Left, Right, Mid,
  InStr, Trim, etc., you can probably figure out from the source code or just
  use it in your programs.
  
  I set up my C++ Parse as a String Class member function that returns void and
  needs to have the token that will be parsed against and the block of memory
  that will manage the parsed Strings as parameters.  So the initial setup will
  involve a pointer to a String Object declaration such as this...
  
  String* pStr=NULL;
  
  This is somewhat analagous to the declaration of the strArr() variable in the
  PowerBASIC program...
  
  Local strArr() As String
  
  Now that C++ pointer to String object declaration will need to point to memory
  where some as yet undetermined number of String objects will lie.  The first
  order of business then is to determine the number of Strings in the main
  String that will need to be parsed.  I have a ParseCount member in my String
  Class that returns that number.  Its implementation is rather trieval in that
  it simply runs through a String object with a char* counting delimiters.  The
  number of Strings will be the number of delimiters counted plus one.  Its use
  is as follows...
  
  String s1("Frederick, John, Harris");
  
  iCount=s1.ParseCount(',');
  pStr=new String[iCount];
  
  Since there are three Strings in the main String we'll need to allocate room
  for three Strings with C++'s new operator.  These would be referenced then as
  
  pStr[0], pStr[1], and pStr[2]
  
  The entire block of memory allocated here will be 24 bytes because each String
  comprises 8 bytes; 4 bytes for private member pStrBuffer and 4 more for
  private member iAllowableCharacterCount.  For sure the parsed Strings don't go
  here.  What goes here is the String object 'overhead' that manages each String
  once it has been parsed.
  
  At this point I believe my narrative should jump to the output from running
  the program.  The first String Constructor call occurs when String s1 is
  declared and initialized simultaneously with a char string...
  
  String s1("Frederick, John, Harris");
  
  Following that is the call to ParseCount and the return of 3.  Then we have
  three more Uninitialized Constructor calls generated by this statement...
  
  pStr=new String[iCount];
  
  If you look at the value of the 'this' pointer you'll see it starts at 4009100
  and increments up to 4009116 in 8 byte increments for the reasons just
  described above.  You can think of this memory as the machinery that manages
  the Strings.  The Strings themselves will be located at the numbers held in
  the pStrBuffer members, and as you can see that memory is scattered about a
  good bit.  When we finally make the call to the Parse member...
  
  s1.Parse(pStr,',');
  
  ...our output jumps inside that function reproduced here without the printf
  statements...
  
  
  void String::Parse(String* pStr, char delimiter)
  {
   unsigned int i=0;
   char* pBuffer=0;
   char* c;
   char* p;

   pBuffer=new char[this->LenStr()+1];
   if(pBuffer)
   {
      p=pBuffer;
      c=this->pStrBuffer;
      while(*c)
      {
         if(*c==delimiter)   //We've hit a delimiter and we know that up to this
         {                   //point a null was copied after each non-delimiter
            pStr[i]=pBuffer; //char.  So we should have a null terminated String
            p=pBuffer;       //at pBuffer that can be directly assigned to one
            i++;             //of the pStr[i] Strings passed in.  Of course i is
         }                   //incremented after each assignment so we're in
         else                //high cotton.
         {
            *p=*c;  //What's pointed at by c isn't a delimiter so copy the char
            p++;    //p=pBuffer and then increment p, i.e., p++.  Then store a
            *p=0;   //null byte at p which is now directly after the last char.
         }
         c++;
      }
      pStr[i]=pBuffer;
      delete [] pBuffer;
   }
  }
  
  The 1st thing my Parse does is allocate a temporary local buffer to slop
  around in.  I make it as big as the original String to be parsed.  Then
  I simply start moving through the String to be parsed pointed to by pStrBuffer
  one byte at a time using a while loop construct.  If the byte pointed at by c
  ( *c ) is not a delimiter, I simply copy that byte to my slop buffer pBuffer.
  Then I increment p and put a null byte after the last character copied because
  the next byte at c could very well be a delimiter, in which case the string
  in pBuffer up to the null will have to be assigned to one of the pStr[i]
  passed in.  
  
  So the loop just keeps doing that, i.e., copying bytes to pBuffer and placing
  a null after each byte, until a delimiter is 'hit'.  When the delimiter is
  hit we're in the upper part of the if and the String accumulated in pBuffer
  is simply assigned to the correct pStr[i] parameter as determined by the i
  counter variable which itself gets incremented after each assignment.
  Interestingly, you can see how the pStr[i]=pBuffer assignment triggered the
  operator= member.  Its all there in the output from within Parse. You can see
  where each of the three Strings were parsed out, and you can see the results
  and all the implicated addresses back in DoProcessing.  Note finally how
  the destructors on all the various Strings were automatically called when
  DoProcessing() terminated.
*/

#include <stdio.h>
#include "Strings.h"

void DoProcessing(void)
{
 String s1("Frederick, John, Harris");
 unsigned int iCount;
 String* pStr=NULL;  
 
 iCount=s1.ParseCount(',');
 printf("iCount = %u\n\n", iCount);
 pStr=new String[iCount];
 printf("pStr   = %u\n\n", (unsigned int)pStr);
 s1.Parse(pStr,',');
 printf("&pStr[i]\tpStr[i].lpStr()\t\tpStr[i].lpStr()\n");
 printf("=======================================================\n");
 for(unsigned int i=0; i<iCount; i++)
 {
     pStr[i].LTrim();
     printf
     (
      "%u\t\t%u\t\t\t%s\n",
      (unsigned int)&pStr[i],(unsigned int)pStr[i].lpStr(),pStr[i].lpStr()
     );
 }    
 delete [] pStr;
 return;      
}    

int main(void)
{
 DoProcessing();
 getchar();  
    
 return 0;  
}


/*
Entering String(const char* pStr)  //Constructor: Initializes with char*
  this = 2293552
  pStr = Frederick, John, Harris
  pStrBuffer = 4009056  Frederick, John, Harris
Leaving String(const char* pStr)

iCount = 3

Entering String()  Uninitialized Constructor
  this = 4009100
  pStrBuffer = 4008952
Leaving Uninitialized Constructor

Entering String()  Uninitialized Constructor
  this = 4009108
  pStrBuffer = 4009136
Leaving Uninitialized Constructor

Entering String()  Uninitialized Constructor
  this = 4009116
  pStrBuffer = 4009152
Leaving Uninitialized Constructor

pStr   = 4009100

Entering Parse(String* pStr, char delimiter)
  pBuffer = 4009168
  Entering String::operator=(const char* pStr)
    pStr = 4009200      Frederick
  Leaving String::operator=(const char* pStr)

  Assigned pStr[0] In Parse()
  pStr[0]  = Frederick
  pStr[0]  = 4009200
  &pStr[i] = 4009100

  Entering String::operator=(const char* pStr)
    pStr = 4009136       John
  Leaving String::operator=(const char* pStr)

  Assigned pStr[1] In Parse()
  pStr[1]  =  John
  pStr[1]  = 4009136
  &pStr[i] = 4009108

  Entering String::operator=(const char* pStr)
    pStr = 4009224       Harris
  Leaving String::operator=(const char* pStr)

  Assigned pStr[2] In Parse()
  pStr[2]  =  Harris
  pStr[2]  = 4009224
  &pStr[i] = 4009116
Leaving Parse(String* pStr, char delimiter)

&pStr[i]        pStr[i].lpStr()         pStr[i].lpStr()
=======================================================
4009100         4009200                 Frederick
4009108         4009136                 John
4009116         4009224                 Harris

Entering String Destructor!
  this       = 4009116
  pStrBuffer = 4009224  Harris
Leaving String Destructor!


Entering String Destructor!
  this       = 4009108
  pStrBuffer = 4009136  John
Leaving String Destructor!


Entering String Destructor!
  this       = 4009100
  pStrBuffer = 4009200  Frederick
Leaving String Destructor!


Entering String Destructor!
  this       = 2293552
  pStrBuffer = 4009056  Frederick, John, Harris
Leaving String Destructor!
*/
« Last Edit: November 26, 2009, 09:13:26 PM by Frederick J. Harris »

Offline Frederick J. Harris

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 938
    • Frederick J. Harris
Re: ProgEx33 -- String.h Header File For Above String Class Example
« Reply #1 on: November 26, 2009, 05:23:39 AM »
Code: [Select]
//Strings.h
#if !defined(STRINGS_H)
#define STRINGS_H
#define EXPANSION_FACTOR      2
#define MINIMUM_ALLOCATION    8

class String
{
 public:
 String();                                //Uninitialized Constructor
 String(const char);                      //Constructor Initializes String With char
 String(const char*);                     //Constructor Initializes String With char*
 String(const String&);                   //Constructor Initializes String With Another String (Copy Constructor)
 String(const int);                       //Constructor Initializes Buffer To Specific Size
 String& operator=(const char);           //Assigns char To String
 String& operator=(const char*);          //Assigns char* To String
 String& operator=(const String&);        //Assigns one String to another (this one)
 String& operator+(const char);           //For adding char to String
 String& operator+(const char*);          //For adding null terminated char array to String
 String& operator+(const String&);        //For adding one String to Another
 bool operator==(const String);           //For comparing Strings
 String Left(unsigned int);               //Returns String of iNum Left Most chars of this
 String Right(unsigned int);              //Returns String of iNum Right Most chars of this
 String Mid(unsigned int, unsigned int);  //Returns String consisting of number of chars from some offset
 String Remove(const char*, bool);        //Returns A String With A Specified char* Removed
 int InStr(const char);                   //Returns one based offset of a specific char in a String
 int InStr(const char*, bool);            //Returns one based offset of a particular char pStr in a String
 int InStr(const String&, bool);          //Returns one based offset of where a particular String is in another String
 void LTrim();                            //Removesleading spaces/tabs
 void RTrim();                            //Removes spaces/tabs from end
 void Trim();                             //Removes both leading and trailing whitespace
 unsigned int ParseCount(const char);     //Returns count of Strings delimited by a char passed as a parameter
 void Parse(String*, char);               //Returns array of Strings in first parameter as delimited by 2nd char delimiter
 String CStr(const int);                  //Converts String to integer
 String CStr(const unsigned int);         //Converts String to unsigned int
 String CStr(const short int);            //Converts String to 16 bit int
 String CStr(const double);               //Converts String to double
 int iVal();                              //Returns int value of a String
 int LenStr(void);                        //Returns length of string
 char* lpStr();                           //Returns address of pStrBuffer member variable
 void Print(bool);                        //Outputs String to Console with or without CrLf
 ~String();                               //String Destructor

 private:
 char* pStrBuffer;
 int   iAllowableCharacterCount;
};
#endif

Offline Frederick J. Harris

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 938
    • Frederick J. Harris
Re: ProgEx33 -- String.cpp File (Implementation Of String Class)
« Reply #2 on: November 26, 2009, 05:25:27 AM »
Code: [Select]
//Strings.cpp
#include  <stdlib.h>
#include  <stdio.h>
#include  <string.h>
#include  "Strings.h"

String::String()    //Uninitialized Constructor
{
 puts("Entering String()  Uninitialized Constructor");   
 pStrBuffer=new char[MINIMUM_ALLOCATION];
 printf("  this = %u\n",(unsigned int)this);
 printf("  pStrBuffer = %u\n",(unsigned int)pStrBuffer);
 pStrBuffer[0]='\0';
 this->iAllowableCharacterCount=MINIMUM_ALLOCATION-1;
 puts("Leaving Uninitialized Constructor\n");   
}


String::String(const char ch)  //Constructor: Initializes with char
{
 pStrBuffer=new char[MINIMUM_ALLOCATION];
 pStrBuffer[0]=ch;
 pStrBuffer[1]='\0';
 iAllowableCharacterCount=MINIMUM_ALLOCATION-1;
}


String::String(const char* pStr)  //Constructor: Initializes with char*
{
 int iLen,iNewSize;

 puts("Entering String(const char* pStr)  //Constructor: Initializes with char*");
 printf("  this = %u\n", (unsigned int)this);
 printf("  pStr = %s\n",pStr);
 iLen=strlen(pStr);
 iNewSize=(iLen/16+1)*16;
 pStrBuffer=new char[iNewSize];
 this->iAllowableCharacterCount=iNewSize-1;
 strcpy(pStrBuffer,pStr);
 printf("  pStrBuffer = %u\t%s\n",(unsigned int)pStrBuffer,pStrBuffer);
 
 puts("Leaving String(const char* pStr)\n");
}


String::String(const String& s)  //Constructor Initializes With Another String, i.e., Copy Constructor
{
 int iLen,iNewSize;

 puts("Entering String(const String& s) Copy Constructor");
 iLen=strlen(s.pStrBuffer);
 iNewSize=(iLen/16+1)*16;
 this->pStrBuffer=new char[iNewSize];
 this->iAllowableCharacterCount=iNewSize-1;
 strcpy(this->pStrBuffer,s.pStrBuffer);
 printf("  this       = %u\n",(unsigned int)this);
 printf("  pStrBuffer = %u\n",(unsigned int)pStrBuffer);
 puts("Leaving String(const String& s) Copy Constructor\n");
}


String::String(const int iSize)  //Constructor Creates String With Custom Sized
{                                //Buffer (rounded up to paragraph boundary)
 int iNewSize;

 iNewSize=(iSize/16+1)*16;
 pStrBuffer=new char[iNewSize];
 this->iAllowableCharacterCount=iNewSize-1;
}


String& String::operator=(const char ch)  //Overloaded operator = for assigning a character to a String
{
 this->pStrBuffer[0]=ch;
 this->pStrBuffer[1]='\0';

 return *this;
}


String& String::operator=(const char* pStr)   //Constructor For If Pointer To Asciiz String Parameter
{
 int iLen,iNewSize;

 puts("  Entering String::operator=(const char* pStr)");
 iLen=strlen(pStr);
 if(iLen<this->iAllowableCharacterCount)
 {
    strcpy(pStrBuffer,pStr);
    printf("    pStr = %u\t%s\n",(unsigned int)pStrBuffer,pStrBuffer);   
 }   
 else
 {
    delete [] pStrBuffer;
    iNewSize=(iLen/16+1)*16;
    pStrBuffer=new char[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
    strcpy(pStrBuffer,pStr);
    printf("    pStr = %u\t%s\n",(unsigned int)pStrBuffer,pStrBuffer);
 }
 puts("  Leaving String::operator=(const char* pStr)\n");

 return *this;
}


String& String::operator=(const String& strRight)  //Overloaded operator = for
{                                                  //assigning another String to
 int iRightLen,iNewSize;                           //a String

 if(this==&strRight)
    return *this;
 iRightLen=strlen(strRight.pStrBuffer);
 if(iRightLen < this->iAllowableCharacterCount)
    strcpy(pStrBuffer,strRight.pStrBuffer);
 else
 {
    iNewSize=(iRightLen/16+1)*16;
    delete [] this->pStrBuffer;
    this->pStrBuffer=new char[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
    strcpy(pStrBuffer,strRight.pStrBuffer);
 }
 
 return *this;
}



bool String::operator==(const String strCompare)
{
 if(strcmp(this->pStrBuffer,strCompare.pStrBuffer)==0)  //strcmp
    return true;
 else
    return false;
}


String& String::operator+(const char ch)      //Overloaded operator + (Puts char in String)
{
 int iLen,iNewSize;
 char* pNew;

 iLen=strlen(this->pStrBuffer);
 if(iLen<this->iAllowableCharacterCount)
 {
    this->pStrBuffer[iLen]=ch;
    this->pStrBuffer[iLen+1]='\0';
 }
 else
 {
    iNewSize=((this->iAllowableCharacterCount*EXPANSION_FACTOR)/16+1)*16;
    pNew=new char[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
    strcpy(pNew,this->pStrBuffer);
    delete [] this->pStrBuffer;
    this->pStrBuffer=pNew;
    this->pStrBuffer[iLen]=ch;
    this->pStrBuffer[iLen+1]='\0';
 }

 return *this;
}


String& String::operator+(const char* pChar) //Overloaded operator + (Adds char literals
{                                             //or pointers to Asciiz Strings)
 int iLen,iNewSize;
 char* pNew;

 iLen=strlen(this->pStrBuffer)+strlen(pChar);
 if(iLen<this->iAllowableCharacterCount)
 {
    if(this->pStrBuffer)
       strcat(this->pStrBuffer,pChar);
    else
       strcpy(this->pStrBuffer, pChar);
 }     
 else
 {
    iNewSize=(iLen*EXPANSION_FACTOR/16+1)*16;
    pNew=new char[iNewSize];
    this->iAllowableCharacterCount = iNewSize-1;   
    if(this->pStrBuffer)
    { 
       strcpy(pNew,this->pStrBuffer);
       delete [] pStrBuffer;
       strcat(pNew,pChar);
    }
    else
       strcpy(pNew,pChar);
    this->pStrBuffer=pNew;
 }

 return *this;
}


String& String::operator+(const String& strRight)  //Overloaded operator + Adds
{                                                  //Another String to the left
 int iLen,iNewSize;                                //operand
 char* pNew;

 iLen=strlen(this->pStrBuffer) + strlen(strRight.pStrBuffer);
 if(iLen < this->iAllowableCharacterCount)
 {
    if(this->pStrBuffer)
       strcat(this->pStrBuffer,strRight.pStrBuffer);
    else
       strcpy(this->pStrBuffer,strRight.pStrBuffer);
 }
 else
 {
    iNewSize=(iLen*EXPANSION_FACTOR/16+1)*16;
    pNew=new char[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;   
    if(this->pStrBuffer)
    {
       strcpy(pNew,this->pStrBuffer);
       delete [] pStrBuffer;
       strcat(pNew,strRight.pStrBuffer);
    }
    else
       strcpy(pNew,strRight.pStrBuffer);
    this->pStrBuffer=pNew;
 }

 return *this;
}


String String::Left(unsigned int iNum)
{
 unsigned int iLen,i,iNewSize;
 String sr;

 iLen=strlen(this->pStrBuffer);
 if(iNum<iLen)
 {
    iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    sr.iAllowableCharacterCount=iNewSize-1;
    sr.pStrBuffer=new char[iNewSize];
    for(i=0;i<iNum;i++)
        sr.pStrBuffer[i]=this->pStrBuffer[i];
    sr.pStrBuffer[iNum]='\0';
    return sr;
 }
 else
 {
    sr=*this;
    return sr;
 }
}


String String::Remove(const char* pToRemove, bool blnCaseSensitive)
{
 int i,j,iParamLen,iReturn=0;
 bool blnFound=false;

 if(*pToRemove==0)
    return true;
 iParamLen=strlen(pToRemove);
 i=0, j=0;
 do
 {
  if(pStrBuffer[i]==0)
     break;
  if(blnCaseSensitive)
     iReturn=strncmp(pStrBuffer+i,pToRemove,iParamLen);  //strncmp
  else
     iReturn=strnicmp(pStrBuffer+i,pToRemove,iParamLen); //_strnicmp
  if(iReturn!=0)
  {
     if(blnFound)
        pStrBuffer[j]=pStrBuffer[i];
     j++, i++;
  }
  else   //made a match
  {
     blnFound=true;
     i=i+iParamLen;
     pStrBuffer[j]=pStrBuffer[i];
     j++, i++;
  }
 }while(1);
 if(blnFound)
    pStrBuffer[i-iParamLen]='\0';
 String sr=pStrBuffer;

 return sr;
}


String String::Right(unsigned int iNum)  //Returns Right$(strMain,iNum)
{
 unsigned int iLen,i,j,iNewSize;
 String sr;

 iLen=strlen(this->pStrBuffer);
 if(iNum<iLen)
 {
    iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    sr.iAllowableCharacterCount=iNewSize-1;
    sr.pStrBuffer=new char[iNewSize];
    j=0;
    for(i=iLen-iNum;i<=iLen;i++)
    {
        //printf(_T("%u\t%u\t%c\n"),i,j,pStrBuffer[i]);
        sr.pStrBuffer[j]=this->pStrBuffer[i];
        j++;
    }
    sr.pStrBuffer[iNum]='\0';
    return sr;
 }
 else
 {
    sr=*this;
    return sr;
 }
}


String String::Mid(unsigned int iStart, unsigned int iCount)
{
 unsigned int iLen,i,j,iNewSize;
 String sr;

 iLen=strlen(this->pStrBuffer);
 if(iStart && iStart<=iLen)
 {
    if(iCount && iStart+iCount-1<=iLen)
    {
       iNewSize=(iCount*EXPANSION_FACTOR/16+1)*16;
       sr. iAllowableCharacterCount=iNewSize-1;
       sr.pStrBuffer=new char[iNewSize];
       j=0;
       sr.pStrBuffer=new char[iNewSize];
       for(i=iStart-1;i<iStart+iCount-1;i++)
       {
           sr.pStrBuffer[j]=this->pStrBuffer[i];
           j++;
       }
       sr.pStrBuffer[iCount]='\0';
       return sr;
    }
    else
    {
       sr=*this;
       return sr;
    }
 }
 else
 {
    sr=*this;
    return sr;
 }
}


int String::InStr(const char ch)
{
 int iLen,i;

 iLen=strlen(this->pStrBuffer);
 for(i=0;i<iLen;i++)
 {
     if(this->pStrBuffer[i]==ch)
        return (i+1);
 }

 return 0;
}


int String::InStr(const char* pStr, bool blnCaseSensitive)
{
 int i,iParamLen,iRange;

 if(*pStr==0)
    return 0;
 iParamLen=strlen(pStr);
 iRange=strlen(pStrBuffer)-iParamLen;
 if(iRange>=0)
 {
    for(i=0;i<=iRange;i++)
    {
        if(blnCaseSensitive)
        {
           if(strncmp(pStrBuffer+i,pStr,iParamLen)==0)   //strncmp
              return i+1;
        }
        else
        {
           if(strnicmp(pStrBuffer+i,pStr,iParamLen)==0)  //_strnicmp
              return i+1;
        }
    }
 }

 return 0;
}


int String::InStr(const String& s, bool blnCaseSensitive)
{
 int i,iParamLen,iRange,iLen;

 iLen=strlen(s.pStrBuffer);
 if(iLen==0)
    return 0;
 iParamLen=iLen;
 iRange=strlen(pStrBuffer)-iParamLen;
 if(iRange>=0)
 {
    for(i=0;i<=iRange;i++)
    {
        if(blnCaseSensitive)
        {
           if(strncmp(pStrBuffer+i,s.pStrBuffer,iParamLen)==0)  //strncmp
              return i+1;
        }
        else
        {
           if(strnicmp(pStrBuffer+i,s.pStrBuffer,iParamLen)==0) //_strnicmp
              return i+1;
        }
    }
 }

 return 0;
}


void String::LTrim()
{
 unsigned int i,iCt=0,iLenStr;

 iLenStr=this->LenStr();
 for(i=0;i<iLenStr;i++)
 {
     if(pStrBuffer[i]==32||pStrBuffer[i]==9)
        iCt++;
     else
        break;
 }
 if(iCt)
 {
    for(i=iCt;i<=iLenStr;i++)
        pStrBuffer[i-iCt]=pStrBuffer[i];
 }
}


void String::RTrim()
{
 unsigned int iCt=0, iLenStr;

 iLenStr=this->LenStr()-1;
 for(unsigned int i=iLenStr; i>0; i--)
 {
     if(this->pStrBuffer[i]==32 || this->pStrBuffer[i]==9)
        iCt++;
     else
        break;
 }
 this->pStrBuffer[this->LenStr()-iCt]=0;
}


void String::Trim()
{
 this->LTrim();
 this->RTrim();
}


unsigned int String::ParseCount(const char c)  //returns one more than # of
{                                              //delimiters so it accurately
 unsigned int iCtr=0;                          //reflects # of strings delimited
 char* p;                                      //by delimiter.

 p=this->pStrBuffer;
 while(*p)
 {
  if(*p==c)
     iCtr++;
  p++;
 }

 return ++iCtr;
}


void String::Parse(String* pStr, char delimiter)
{
 unsigned int i=0;
 char* pBuffer=0;
 char* c;
 char* p;

 puts("Entering Parse(String* pStr, char delimiter)");
 pBuffer=new char[this->LenStr()+1];
 printf("  pBuffer = %u\n",(unsigned int)pBuffer);
 if(pBuffer)
 {
    p=pBuffer;
    c=this->pStrBuffer;
    while(*c)
    {
     if(*c==delimiter)
     {
        pStr[i]=pBuffer;
        printf("  Assigned pStr[%u] In Parse()\n",i);
        printf("  pStr[%u]  = %s\n",i,pStr[i].lpStr());
        printf("  pStr[%u]  = %u\n",i,(unsigned int)pStr[i].lpStr());
        printf("  &pStr[i] = %u\n\n",(unsigned int)&pStr[i]);
        p=pBuffer;
        i++;
     }
     else
     {
        *p=*c;
        p++;
        *p=0;
     }
     c++;
    }
    pStr[i]=pBuffer;
    printf("  Assigned pStr[%u] In Parse()\n",i);
    printf("  pStr[%u]  = %s\n",i,pStr[i].lpStr());
    printf("  pStr[%u]  = %u\n",i,(unsigned int)pStr[i].lpStr());
    printf("  &pStr[i] = %u\n",(unsigned int)&pStr[i]);
    delete [] pBuffer;
 }
 puts("Leaving Parse(String* pStr, char delimiter)\n");
}


int String::iVal()
{
 return atoi(this->pStrBuffer);  //atoi
}


String String::CStr(const int iNum)
{
 String sr;
 sprintf(sr.pStrBuffer,"%d",iNum);
 return sr;
}


String String::CStr(const unsigned int iNum)
{
 String sr;
 sprintf(sr.pStrBuffer,"%u",iNum);
 return sr;
}


String String::CStr(const short int iNum)
{
 String sr;
 sprintf(sr.pStrBuffer,"%d",iNum);
 return sr;
}


String String::CStr(const double dblNum)
{
 String sr(32);
 sprintf(sr.pStrBuffer,"%f",dblNum);
 return sr;
}


int String::LenStr(void)
{
 return strlen(this->pStrBuffer);
}


char* String::lpStr()
{
 return pStrBuffer;
}


void String::Print(bool blnCrLf)
{
 printf("%s",pStrBuffer);
 if(blnCrLf)
    printf("\n");
}


String::~String()   //String Destructor
{
 printf("\nEntering String Destructor!\n");
 printf("  this       = %u\n", (unsigned int)this);
 printf("  pStrBuffer = %u\t%s\n",(unsigned int)pStrBuffer,pStrBuffer); 
 delete [] pStrBuffer;
 pStrBuffer=0;
 printf("Leaving String Destructor!\n\n");
}

Offline Frederick J. Harris

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 938
    • Frederick J. Harris
Case Sensitive Example Of InStr() With C++ String Class
« Reply #3 on: November 26, 2009, 05:29:31 AM »
Code: [Select]
//Case Sensitive Search For Substring Using .InStr()
#include <stdio.h>
#include "Strings.h"

int main(void)
{
 String s1("Frederick John Harris");
 int iLoc=0;
 
 iLoc=s1.InStr("John", true);
 if(iLoc)
    printf("The Sub String 'John' Is Contained In s1 And Begins At %d\n",iLoc);
 else
    printf("The Sub String 'John' Is Not Contained In s1\n");
 getchar();   
   
 return 0;   
}


/*
Entering String(const char* pStr)  //Constructor: Initializes with char*
  this = 2293584
  pStr = Frederick John Harris
  pStrBuffer = 4072496  Frederick John Harris
Leaving String(const char* pStr)

The Sub String 'John' Is Contained In s1 And Begins At 11
*/

Offline Frederick J. Harris

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 938
    • Frederick J. Harris
Re: ProgEx33 -- Non-Case Sensitive InStr Example
« Reply #4 on: November 26, 2009, 05:32:02 AM »
Code: [Select]
//Non-Case Sensitive Search For Substring Using .InStr()
#include <stdio.h>
#include "Strings.h"

int main(void)
{
 String s1("Frederick John Harris");
 int iLoc=0;
 
 iLoc=s1.InStr("john", false);  //use false for 2nd parameter
 if(iLoc)
    printf("The Sub String 'John' Is Contained In s1 And Begins At %d\n",iLoc);
 else
    printf("The Sub String 'John' Is Not Contained In s1\n");
 getchar();   
   
 return 0;   
}

/*
The Sub String 'John' Is Contained In s1 And Begins At 11
*/

Offline Frederick J. Harris

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 938
    • Frederick J. Harris
Re: ProgEx33 -- C++ String Class Left, Right, Mid Example
« Reply #5 on: November 26, 2009, 05:33:42 AM »
Code: [Select]
/*
  Here would be kind of a work example for me that shows a common use of mine
  for Left, Right, and Mid.  Our foresters put their 100% tally timber marking
  data collector files (I wrote the programs with PB DOS) in C:\Tallies\RawData.
  The files have a *.mrk (mark) extension.  My desktop PowerBASIC program reads
  the binary file and creates an Access database containing the data in...
 
  C:\Tallies\DBFiles\SaleName.mdb
 
  where SaleName.mdb would be something like 15200901.mdb for the 1st sale in
  our District 15 for 2009.  So you start with a data collector file name and
  location such as this...
 
  C:\\Tallies\\RawData\\15200901.mrk
 
  and need to parse that string and create an Access database such as this...
 
  C:\\Tallies\\DBFiles\\15200901.mdb
*/


#include <stdio.h>
#include "Strings.h"

int main(void)
{
 String s1("C:\\Tallies\\RawData\\15200901.mrk");
 String s2,s3;
 
 s2=s1.Left(11);
 s2.Print(true);
 s3=s1.Mid(20,8);
 s3.Print(true);
 s2=s2+"DBFiles\\"+s3+".mdb";
 s2.Print(true);
 getchar();   
   
 return 0;   
}

/*
C:\Tallies\
15200901
C:\Tallies\DBFiles\15200901.mdb
*/

Offline Patrice Terrier

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1998
    • www.zapsolution.com
Re: ProgEx33 -- C++ Version Of String::Parse And String::ParseCount
« Reply #6 on: February 14, 2013, 07:45:06 PM »
Frederick,

Do you have a UNICODE version of your string class?

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Frederick J. Harris

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 938
    • Frederick J. Harris
Re: ProgEx33 -- C++ Version Of String::Parse And String::ParseCount
« Reply #7 on: February 15, 2013, 10:58:11 PM »
Quote
Do you have a UNICODE version of your string class?


Yes, why donít I just post it in your forum Patrice, rather than making you hunt for it through that big COM tutorial of mine on the grid control?  The Strings.h and Strings.cpp files are actually at Reply #42 here Ö

http://www.jose.it-berater.org/smfforum/index.php?topic=4176.0

But Iíll post it up in your forum.  That Example 33 tutorial is my old String Class that I really need to update, as I donít use that one anymore.  What happened there is that I was working hard on that String Processing Comparison I posted about a long time ago in the PowerBASIC Forums, where I was comparing C, C++, and PowerBASIC String processing speeds, and in the process of doing that I had to redo my string class because I found that my concatenation operation was much, much slower than the one in the C++ Standard Library String Class, and I wanted to improve it.  In that tutorial example there were only two member variables in my String Class, and I added a third which cached the String length, rather than continuously calling the strlen() function, which was killing my performance.