VC++
Example: CString Extension,
Get Window Directory
|
|
Download
Source Code
There are innumerable
MFC functions that
need a CString object
as an argument or return a CString
object. Often, even if a function needs a char pointer, we
still use a CString to
hold the string. Although, the CString class has lots of
features, it does lack a few very useful string
manipulation functions. A case insensitive search funciton
is one, a search and replace function is another.
Fortunately, implementing these functionality is not very
difficult. The CStringEx class given below derives from CString
and adds a few useful functions. The CStringEx class does
not add any member variables of its own, so that it can be
freely interchanged with a CString object.
The constructors in the
CStringEx class parallel the constructor in CString and in
fact simply chains into the corresponding CString
constructor. Some of the CStringEx functions use knowledge
of the internal structure of the CString
object so there is a small chance that these functions
might break if the CString
implementation changes.
The functions provided by
CStringEx are quite easy to use and fairly simple to
understand. The Insert() functions inserts a character or
a sub-string within a string. The result is similar to
inserting text in an edit control, the string is expanded
to accommodate the sub-string. The Delete() function
removes a segment from the string and shortens it. The
Replace() function removes a sub-string and replaces it
with another. Again, the string size is adjusted depending
on the size of the sub-string that was removed and the
size of the sub-string that was inserted.
The find family of
functions, finds a sub-string in the forward or the
reverse direction. The NoCase version of these functions
are case insensitive. The FindReplace() and
FindReplaceNoCase() functions searches for a sub-string
and replaces the matching sub-string with another string.
The GetField() and GetDelimitedField() functions find a
token in the string. The table below exemplifies the uses
of these functions.
Also included are four
public member functions:
void GetWindowsDirectory();
void GetSystemDirectory();
void GetCurrentDirectory();
void GetDateDirectory();
Calling either of these
functions will REPLACE the current string contents with
the content described by the function name.
Example:
CStringEx strTarget="[systemdir]";
printf(strTarget);
//output:
c:\windows\system\
another example:
CStringEx strTarget="c:\\outbox\\sessions[datedir]\\incoming";
printf(strTarget);
//output:
d:\outbox\sessions\08061998\incoming\
last but not least:
CStringEx strTarget;
strTarget.GetCurrentDirectory();
printf(strTarget);
//output:
c:\Program Files\
If you have any changes, new macros or perhaps I missed something, please email me. The source code:
String
|
Function
|
Result
|
xyz
|
Insert(1,
‘a’)
|
xayz
|
xyz
|
Insert(1, "ab")
|
xabyz
|
xyz
|
Insert(4, "ab")
|
xyz ab
|
Abcde
|
Delete(2,2)
|
Abe
|
Abcde
|
Replace(2,2,"xyz")
|
Abxyze
|
Abc
|
Find(‘b’)
|
1
|
Abcabc
|
Find(‘b’, 2)
|
4
|
AbcAbc
|
FindNoCase("aBC",
1)
|
3
|
AbcAbc
|
FindReplace("Ab","Xy")
|
XycXyc
|
AbcAbc
|
FindReplace("Ab","Xy",
FALSE)
|
XycAbc
|
AbcAbc
|
FindReplaceNoCase("ab","Xy")
|
XycXyc
|
AbcAbc
|
FindReplaceNoCase("ab","Xy",
FALSE)
|
XycAbc
|
AbcAbc
|
ReverseFind("bc")
|
4
|
AbcAbc
|
ReverseFindNoCase("abc")
|
3
|
AbcAbc
|
ReverseFindNoCase("abc",
2)
|
0
|
AbcAbc
|
GetField(
‘:’, 0 )
|
AbcAbc
|
AbcAbc
|
GetField(
‘:’, 1 )
|
(Blank string)
|
Abc:Def
|
GetField(
‘:’, 0 )
|
Abc
|
Abc:Def
|
GetField(
‘:’, 1 )
|
Def
|
Abc:Def
|
GetField(
‘:’, 2 )
|
(Blank string)
|
Name: Zafir
|
GetField("Name:
", 1)
|
Zafir
|
(415) 555-7777
|
GetDelimitedField("(",
")", 0 )
|
415
|
//////////////////////////////////////////////////////////////////////
// StringEx.h
//
#ifndef __STRINGEX_H_
#define __STRINGEX_H_
class CStringEx : public CString
{
public:
CStringEx() : CString( ){};
CStringEx( const CString& stringSrc) : CString( stringSrc ){};
CStringEx( const CStringEx& stringSrc) : CString( stringSrc ){};
CStringEx( TCHAR ch, int nRepeat = 1 ) : CString( ch, nRepeat ){};
CStringEx( LPCTSTR lpch, int nLength ) : CString( lpch, nLength ){};
CStringEx( const unsigned char* psz ) : CString( psz ){};
CStringEx( LPCWSTR lpsz ) : CString( lpsz ){};
CStringEx( LPCSTR lpsz ) : CString( lpsz ){};
CStringEx& Insert(int pos, LPCTSTR s);
CStringEx& Insert(int pos, TCHAR c);
CStringEx& Delete(int pos, int len);
CStringEx& Replace(int pos, int len, LPCTSTR s);
int Find( TCHAR ch, int startpos = 0 ) const;
int Find( LPCTSTR lpszSub, int startpos = 0 ) const;
int FindNoCase( TCHAR ch, int startpos = 0 ) const;
int FindNoCase( LPCTSTR lpszSub, int startpos = 0 ) const;
int FindReplace( LPCTSTR lpszSub, LPCTSTR lpszReplaceWith, BOOL bGlobal = TRUE );
int FindReplaceNoCase( LPCTSTR lpszSub, LPCTSTR lpszReplaceWith,
BOOL bGlobal = TRUE );
int ReverseFind( TCHAR ch ) const{ return CString::ReverseFind(ch);};
int ReverseFind( LPCTSTR lpszSub, int startpos = -1 ) const;
int ReverseFindNoCase( TCHAR ch, int startpos = -1 ) const;
int ReverseFindNoCase( LPCTSTR lpszSub, int startpos = -1 ) const;
CStringEx GetField( LPCTSTR delim, int fieldnum);
CStringEx GetField( TCHAR delim, int fieldnum);
int GetFieldCount( LPCTSTR delim );
int GetFieldCount( TCHAR delim );
CStringEx GetDelimitedField( LPCTSTR delimStart, LPCTSTR delimEnd,
int fieldnum = 0);
void GetWindowsDirectory();
void GetSystemDirectory();
void GetCurrentDirectory();
void GetDateDirectory();
void Fixate();
void ProcessMacros(const char* szSrc);
protected:
void ExpandMacro(char* pchMacroString);
int GetMacroIndex(char* pchMacroString);
void Concat(const char* pchString);
void GetDateString(char* pchBuffer);
};
#endif
/////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// StringEx.cpp
//
#include "stdafx.h"
#include "StringEx.h"
// Insert - Inserts a sub string into the string
// Returns - Reference to the same string object
// pos - Position to insert at. Extends the string with spaces if needed
// s - Sub string to insert
CStringEx& CStringEx::Insert(int pos, LPCTSTR s)
{
int len = lstrlen(s);
if ( len == 0 )
return *this;
int oldlen = GetLength();
int newlen = oldlen + len;
LPTSTR str;
if ( pos >= oldlen )
{
// insert after end of string
newlen += pos - oldlen ;
str = GetBuffer( newlen );
_tcsnset( str+oldlen, _T(' '), pos-oldlen );
_tcsncpy( str+pos, s, len );
}
else
{
// normal insert
str = GetBuffer( newlen );
memmove( str+pos+len, str+pos, sizeof(_T(' ')) *(oldlen-pos) );
_tcsncpy( str+pos, s, len );
}
ReleaseBuffer( newlen );
return *this;
}
// Insert - Inserts a character into the string
// Returns - Reference to the same string object
// pos - Position to insert at. Extends the string with spaces if needed
// c - Char to insert
CStringEx& CStringEx::Insert(int pos, TCHAR c)
{
TCHAR buf[2];
buf[0] = c;
buf[1] = _T('\0');
return Insert( pos, buf );
}
// Delete - Deletes a segment of the string and resizes it
// Returns - Reference to the same string object
// pos - Position of the string segment to remove
// len - Number of characters to remove
CStringEx& CStringEx::Delete(int pos, int len)
{
int strLen = GetLength();
if( pos >= strLen)
return *this;
if(len < 0 ||len > strLen - pos)
len = strLen - pos;
LPTSTR str = GetBuffer( strLen );
memmove(str+pos, str+pos+len, sizeof(_T(' ')) *(strLen-pos));
ReleaseBuffer( strLen - len );
return *this;
}
// Replace - Replaces a substring with another
// Returns - Reference to the same string object
// pos - Position of the substring
// len - Length of substring to be replaced
// s - New substring
CStringEx& CStringEx::Replace(int pos, int len, LPCTSTR s)
{
Delete(pos, len);
Insert(pos, s);
return *this;
}
// Find - Finds the position of a character in a string
// Returns - A zero-based index
// ch - Character to look for
// startpos - Position to start looking from
int CStringEx::Find( TCHAR ch, int startpos /*= 0*/ ) const
{
// find first single character
LPTSTR lpsz = _tcschr(m_pchData + startpos, (_TUCHAR)ch);
// return -1 if not found and index otherwise
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
// Find - Finds the position of a substring in a string
// Returns - A zero-based index
// lpszSub - Substring to look for
// startpos - Position to start looking from
int CStringEx::Find( LPCTSTR lpszSub, int startpos /*= 0*/ ) const
{
ASSERT(AfxIsValidString(lpszSub, FALSE));
// find first matching substring
LPTSTR lpsz = _tcsstr(m_pchData+startpos, lpszSub);
// return -1 for not found, distance from beginning otherwise
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
// FindNoCase - Case insensitive find
// Returns - A zero-based index
// ch - Char to search for
// startpos - Position to start looking from
int CStringEx::FindNoCase( TCHAR ch, int startpos /*= 0*/ ) const
{
unsigned int locase = Find( tolower( ch ), startpos );
unsigned int upcase = Find( toupper( ch ), startpos );
return locase < upcase ? locase : upcase;
}
// FindNoCase - Case insensitive find
// Returns - A zero-based index
// lpszSub - Substring to search for
// startpos - Position to start looking from
int CStringEx::FindNoCase( LPCTSTR lpszSub, int startpos /*= 0*/ ) const
{
CStringEx sLowerThis = *this;
sLowerThis.MakeLower();
CStringEx sLowerSub = lpszSub;
sLowerSub.MakeLower();
return sLowerThis.Find( sLowerSub, startpos );
}
// FindReplace - Find a substring and replace with another
// Returns - Number of instances replaced
// lpszSub - Substring to look for
// lpszReplaceWith - Substring to replace with
// bGlobal - Flag to indicate whether all occurances
// should be replaced
int CStringEx::FindReplace( LPCTSTR lpszSub, LPCTSTR lpszReplaceWith,
BOOL bGlobal /*= TRUE*/ )
{
int iReplaced = 0;
// find first matching substring
LPTSTR lpsz;
int pos = 0;
int lenSub = lstrlen( lpszSub );
int lenReplaceWith = lstrlen( lpszReplaceWith );
while( (lpsz = _tcsstr(m_pchData + pos, lpszSub)) != NULL )
{
pos = (int)(lpsz - m_pchData);
Replace( pos, lenSub, lpszReplaceWith );
pos += lenReplaceWith;
iReplaced++;
if( !bGlobal ) break;
}
return iReplaced;
}
void CStringEx::ProcessMacros(const char* szSrc)
{
if(!szSrc)
{
return;
}
int nOriginalLength=strlen(szSrc);
char* pchOriginal=new char[nOriginalLength+1];
strcpy(pchOriginal,szSrc);
Release();
char* pchAnchor=pchOriginal;
char* pchLead=strchr(pchOriginal,'[');
while(pchLead)
{
if(pchLead!=pchAnchor)
{
pchLead[0]=0;
Concat(pchAnchor);
pchLead[0]='[';
}
pchAnchor=pchLead;
//scan through to the end of macro
pchLead=strchr(pchLead,']');
if(pchLead)
{
pchLead[0]=0;
pchAnchor++;
ExpandMacro(pchAnchor);
pchLead[0]=']';
pchAnchor=pchLead;
pchAnchor++;
pchLead=strchr(pchLead,'[');
}
else
{
break;
}
}
if(strlen(pchAnchor))
{
Concat(pchAnchor);
}
delete[] pchOriginal;
Fixate();
}
void CStringEx::ExpandMacro(char* pchMacroString)
{
if(pchMacroString)
{
char szTemp[MAX_PATH];
switch(GetMacroIndex(pchMacroString))
{
case 0:
::GetWindowsDirectory(szTemp,MAX_PATH);
break;
case 1:
::GetSystemDirectory(szTemp,MAX_PATH);
break;
case 2:
::GetCurrentDirectory(MAX_PATH,szTemp);
break;
case 3:
GetDateString(szTemp);
break;
default:
//unknown macro, return
return;
}
if(szTemp[strlen(szTemp)-1]!=92)
{
strcat(szTemp,"\\");
}
Concat(szTemp);
}
}
void CStringEx::Concat(const char* pchString)
{
CStringData* pOldData = GetData();
ConcatCopy(GetData()->nDataLength, m_pchData, strlen(pchString),pchString);
ASSERT(pOldData != NULL);
CString::Release(pOldData);
}
void CStringEx::GetWindowsDirectory()
{
char szTemp[MAX_PATH];
::GetWindowsDirectory(szTemp,MAX_PATH);
*this=szTemp;
Fixate();
}
void CStringEx::GetSystemDirectory()
{
char szTemp[MAX_PATH];
::GetSystemDirectory(szTemp,MAX_PATH);
*this=szTemp;
Fixate();
}
void CStringEx::GetCurrentDirectory()
{
char szTemp[MAX_PATH];
::GetCurrentDirectory(MAX_PATH,szTemp);
*this=szTemp;
Fixate();
}
void CStringEx::GetDateDirectory()
{
char szTemp[MAX_PATH];
GetDateString(szTemp);
*this=szTemp;
Fixate();
}
void CStringEx::GetDateString(char* pchBuffer)
{
if(!pchBuffer)
{
return;
}
char szTemp[5];
SYSTEMTIME now;
GetLocalTime(&now);
sprintf(pchBuffer,"%02d",now.wDay);
sprintf(szTemp,"%02d",now.wMonth);
strcat(pchBuffer,szTemp);
sprintf(szTemp,"%04d",now.wYear);
strcat(pchBuffer,szTemp);
}
void CStringEx::Fixate()
{
if(m_pchData[GetLength()-1]!=92)
{
*this+="\\";
}
}
int CStringEx::GetMacroIndex(char* pchMacroString)
{
if(!pchMacroString)
{
return -1;
}
if(strcmp(pchMacroString,"windowsdir")==0)
{
return 0;
}
if(strcmp(pchMacroString,"systemdir")==0)
{
return 1;
}
if(strcmp(pchMacroString,"currentdir")==0)
{
return 2;
}
if(strcmp(pchMacroString,"datedir")==0)
{
return 3;
}
return -1;
}
// FindReplaceNoCase - Find a substring and replace with another
// Does case insensitive search
// Returns - Number of instances replaced
// lpszSub - Substring to look for
// lpszReplaceWith - Substring to replace with
// bGlobal - Flag to indicate whether all occurances
// should be replaced
int CStringEx::FindReplaceNoCase( LPCTSTR lpszSub, LPCTSTR lpszReplaceWith,
BOOL bGlobal /*= TRUE*/ )
{
CStringEx sLowerThis = *this;
sLowerThis.MakeLower();
CStringEx sLowerSub = lpszSub;
sLowerSub.MakeLower();
int iReplaced = 0;
// find first matching substring
LPTSTR lpsz;
int pos = 0, offset = 0;
int lenSub = lstrlen( lpszSub );
int lenReplaceWith = lstrlen( lpszReplaceWith );
while( (lpsz = _tcsstr(sLowerThis.m_pchData + pos, sLowerSub.m_pchData)) != NULL )
{
pos = (int)(lpsz - sLowerThis.m_pchData);
Replace( pos+offset, lenSub, lpszReplaceWith );
offset += lenReplaceWith - lenSub;
pos += lenSub;
iReplaced++;
if( !bGlobal ) break;
}
return iReplaced;
}
// ReverseFind - Searches for the last match of a substring
// Returns - A zero-based index
// lpszSub - Substring to search for
// startpos - Position to start looking from, in reverse dir
int CStringEx::ReverseFind( LPCTSTR lpszSub, int startpos /*= -1*/ ) const
{
int lenSub = lstrlen( lpszSub );
int len = lstrlen( m_pchData );
if(0 < lenSub && 0 < len)
{
if( startpos == -1 || startpos >= len ) startpos = len - 1;
for ( LPTSTR lpszReverse = m_pchData + startpos ;
lpszReverse != m_pchData ; --lpszReverse)
if (_tcsncmp(lpszSub, lpszReverse, lenSub ) == 0)
return (lpszReverse - m_pchData);
}
return -1;
}
// ReverseFindNoCase - Searches for the last match of a substring
// Search is case insensitive
// Returns - A zero-based index
// lpszSub - Character to search for
// startpos - Position to start looking from, in reverse dir
int CStringEx::ReverseFindNoCase(TCHAR ch, int startpos /*= -1*/ ) const
{
TCHAR a[2];
a[0] = ch;
a[1] = 0;
return ReverseFindNoCase( a, startpos );
}
// ReverseFindNoCase - Searches for the last match of a substring
// Search is case insensitive
// Returns - A zero-based index
// lpszSub - Substring to search for
// startpos - Position to start looking from, in reverse dir
int CStringEx::ReverseFindNoCase( LPCTSTR lpszSub, int startpos /*= -1*/ ) const
{
//LPTSTR lpszEnd = m_pchData + lstrlen
int lenSub = lstrlen( lpszSub );
int len = lstrlen( m_pchData );
if(0 < lenSub && 0 < len)
{
if( startpos == -1 || startpos >= len ) startpos = len - 1;
for ( LPTSTR lpszReverse = m_pchData + startpos ;
lpszReverse >= m_pchData ; --lpszReverse)
if (_tcsnicmp(lpszSub, lpszReverse, lenSub ) == 0)
return (lpszReverse - m_pchData);
}
return -1;
}
// GetField - Gets a delimited field
// Returns - A CStringEx object that contains a copy of
// the specified field
// delim - The delimiter string
// fieldnum - The field index - zero is the first
// NOTE - Returns the whole string for field zero
// if delim not found
// Returns empty string if # of delim found
// is less than fieldnum
CStringEx CStringEx::GetField( LPCTSTR delim, int fieldnum)
{
LPTSTR lpsz, lpszRemainder = m_pchData, lpszret;
int retlen, lenDelim = lstrlen( delim );
while( fieldnum-- >= 0 )
{
lpszret = lpszRemainder;
lpsz = _tcsstr(lpszRemainder, delim);
if( lpsz )
{
// We did find the delim
retlen = lpsz - lpszRemainder;
lpszRemainder = lpsz + lenDelim;
}
else
{
retlen = lstrlen( lpszRemainder );
lpszRemainder += retlen; // change to empty string
}
}
return Mid( lpszret - m_pchData, retlen );
}
// GetField - Gets a delimited field
// Returns - A CStringEx object that contains a copy of
// the specified field
// delim - The delimiter char
// fieldnum - The field index - zero is the first
// NOTE - Returns the whole string for field zero
// if delim not found
// Returns empty string if # of delim found
// is less than fieldnum
CStringEx CStringEx::GetField( TCHAR delim, int fieldnum)
{
LPTSTR lpsz, lpszRemainder = m_pchData, lpszret;
int retlen;
while( fieldnum-- >= 0 )
{
lpszret = lpszRemainder;
lpsz = _tcschr(lpszRemainder, (_TUCHAR)delim);
if( lpsz )
{
// We did find the delim
retlen = lpsz - lpszRemainder;
lpszRemainder = lpsz + 1;
}
else
{
retlen = lstrlen( lpszRemainder );
lpszRemainder += retlen; // change to empty string
}
}
return Mid( lpszret - m_pchData, retlen );
}
// GetFieldCount - Get number of fields in a string
// Returns - The number of fields
// Is always greater than zero
// delim - The delimiter character
int CStringEx::GetFieldCount( TCHAR delim )
{
TCHAR a[2];
a[0] = delim;
a[1] = 0;
return GetFieldCount( a );
}
// GetFieldCount - Get number of fields in a string
// Returns - The number of fields
// Is always greater than zero
// delim - The delimiter string
int CStringEx::GetFieldCount( LPCTSTR delim )
{
LPTSTR lpsz, lpszRemainder = m_pchData;
int lenDelim = lstrlen( delim );
int iCount = 1;
while( (lpsz = _tcsstr(lpszRemainder, delim)) != NULL )
{
lpszRemainder = lpsz + lenDelim;
iCount++;
}
return iCount;
}
// GetDelimitedField - Finds a field delimited on both ends
// Returns - A CStringEx object that contains a copy of
// the specified field
// delimStart - Delimiter at the start of the field
// delimEnd - Delimiter at the end of the field
CStringEx CStringEx::GetDelimitedField( LPCTSTR delimStart, LPCTSTR delimEnd, int fieldnum /*= 0*/)
{
LPTSTR lpsz, lpszEnd, lpszRet, lpszRemainder = m_pchData ;
int lenDelimStart = lstrlen( delimStart ), lenDelimEnd = lstrlen( delimEnd );
while( fieldnum-- >= 0 )
{
lpsz = _tcsstr(lpszRemainder, delimStart);
if( lpsz )
{
// We did find the Start delim
lpszRet = lpszRemainder = lpsz + lenDelimStart;
lpszEnd = _tcsstr(lpszRemainder, delimEnd);
if( lpszEnd == NULL ) return"";
lpszRemainder = lpsz + lenDelimEnd;
}
else return "";
}
return Mid( lpszRet - m_pchData, lpszEnd - lpszRet );
}
|