/*
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!
*/
//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
//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");
}
//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
*/
//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
*/
/*
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
*/
Frederick,
Do you have a UNICODE version of your string class?
...
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.