Files

489 lines
14 KiB
C++

//------------------------------------------------------------------------------
// FILE NAME: StringParser.cpp
// HEADER: StringParser.h
//
// PURPOSE: Implementation of the CStringParser class.
//
// DESCRIPTION: This class acepts a string and immediately parses it into
// separate fields based on the delimiter character specified by
// the programmer. The separated fields are stored in a
// CStringArray, and the 0th element in the array contains the
// original string. Access to the separated fields is 1-based
// (the first field is in index 1, and so on).
//
// If you are parsing quoted strings, it is IMPARATIVE that the
// quoted strings be formatted correctly. Otherwise you will get
// what appears to be bizarre results.
//
// DISCLAIMER: At first glance, it may seem like the code is somewhat verbose
// and I might have taken the long way around to perform some
// tasks, but I think it makes it easier for someone else to follow
// when I do that. Maintainability is probably the most important
// aspect of coding (after reliability of course).
//
// CHANGE HISTORY:
// DATE INIT CHANGE DESCRIPTION
// -------- ---- --------------------------------------------------------
// 07/20/2000 jms Initial code completed.
// 08/09/2000 jms Added a way to submit a new string to facilitate the use
// of the same object instance when a subsewquent string
// needs to be parsed.
// 01/12/2001 jms Added a way to find strings withion the parsed results.
// 01/20/2001 jms Added support for quoted strings.
//------------------------------------------------------------------------------
#include "stdafx.h"
#include "StringParser.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//------------------------------------------------------------------------------
// NAME: CStringParser::CStringParser()
//
// PURPOSE: Constructor - initializes the array of strings and calls the
// ParseString() function.
//
// PARMETERS: CString sString The string to be parsed
// char cDelimiter The delimiter character used to parse the
// string
//
// RETURNS: N/A
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 07/20/2000 jms Initial development.
//------------------------------------------------------------------------------
CStringParser::CStringParser(CString sString, char cDelimiter)
{
m_aStrings.SetSize(0,10);
ResetOriginalString(sString, cDelimiter);
}
//------------------------------------------------------------------------------
// NAME: CStringParser::CStringParser()
//
// PURPOSE: Constructor - initializes the array of strings and calls the
// ParseString() function.
//
// PARMETERS: CString sString The string to be parsed.
// char cDelimiter The delimiter character used to parse the
// string.
// char cQuoter The quote character we should be looking
// for.
//
// RETURNS: N/A
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- --------------------------------------------------------
// 01/20/2001 jms Added overloaded version of constructor to support
// quoted strings.
//------------------------------------------------------------------------------
CStringParser::CStringParser(CString sString, char cDelimiter, char cQuoter)
{
m_aStrings.SetSize(0,10);
ResetOriginalString(sString, cDelimiter, cQuoter);
}
//------------------------------------------------------------------------------
// NAME: CStringParser::CStringParser()
//
// PURPOSE: Constructor - does nothing
//
// PARMETERS: CString sString The string to be parsed.
//
// RETURNS: N/A
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- --------------------------------------------------------
// 04/25/2001 jc Added overloaded version of constructor to support
// initialization without other data
//------------------------------------------------------------------------------
CStringParser::CStringParser()
{
m_aStrings.SetSize(0,10);
}
//------------------------------------------------------------------------------
// NAME: CStringParser::~CStringParser()
//
// PURPOSE: Destructor - removes all of the array elements from the
// CStringArray.
//
// PARMETERS: None
//
// RETURNS: None
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 07/20/2000 jms Initial development.
// 08/09/2000 jms Added call to new Clear() function.
//------------------------------------------------------------------------------
CStringParser::~CStringParser()
{
Clear();
}
//------------------------------------------------------------------------------
// NAME: CStringParser::Clear()
//
// PURPOSE: Clears the string table.
//
// PARMETERS: None
//
// RETURNS: None
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 08/09/2000 jms Added function.
//------------------------------------------------------------------------------
void CStringParser::Clear()
{
if (m_nCount > 0)
{
m_aStrings.RemoveAll();
}
}
//------------------------------------------------------------------------------
// NAME: CStringParser::ResetOriginalString()
//
// PURPOSE: Clears the string table.
//
// PARMETERS: None
//
// RETURNS: None
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 08/09/2000 jms Added function.
//------------------------------------------------------------------------------
void CStringParser::ResetOriginalString(CString sString, char cDelimiter)
{
Clear();
m_aStrings.Add(sString);
m_cDelimiter = cDelimiter;
m_cQuoter = '\0';
m_nCount = 0;
ParseString();
}
//------------------------------------------------------------------------------
// NAME: CStringParser::ResetOriginalString()
//
// PURPOSE: Clears the string table.
//
// PARMETERS: None
//
// RETURNS: None
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 08/09/2000 jms Added function.
//------------------------------------------------------------------------------
void CStringParser::ResetOriginalString(CString sString, char cDelimiter, char cQuoter)
{
Clear();
m_aStrings.Add(sString);
m_cDelimiter = cDelimiter;
m_cQuoter = cQuoter;
m_nCount = 0;
ParseStringWithQuoter();
}
//------------------------------------------------------------------------------
// NAME: CStringParser::GetField()
//
// PURPOSE: Returns the CString stored in the array element specified by
// the nIndex parameter. If the specified index is greater than
// the number of elements, it is an error.
//
// PARMETERS: int nIndex The index of the desired array item.
//
// RETURNS: CString sBuffer the string retrieved from the array.
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 07/20/2000 jms Initial development.
//------------------------------------------------------------------------------
CString CStringParser::GetField(int nIndex)
{
CString sBuffer;
sBuffer.Empty();
if (m_nCount >= nIndex)
{
sBuffer = m_aStrings.GetAt(nIndex);
}
else
{
sBuffer = "ERROR: Array index out of range.";
}
return sBuffer;
}
//------------------------------------------------------------------------------
// NAME: CStringParser::ParseString()
//
// PURPOSE: Separates the fields out of a copy of the original string by
// searching for the specified delimiter character. As the string
// is searched, it becomes shorter by deleting the most recently
// found field (and the next delimiter, if one exists) from the
// beginning of itself.
//
// PARMETERS: None
//
// RETURNS: int The number of fields found in the original string.
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 07/20/2000 jms Initial development.
//------------------------------------------------------------------------------
int CStringParser::ParseString()
{
// get a copy of the string
CString sWorkString = GetOriginalString();
CString sBuffer;
int pos = 0;
m_nCount = 0;
// while the string is not empty...
while (!sWorkString.IsEmpty())
{
// find the position of the next delimiter
pos = sWorkString.Find(m_cDelimiter);
// if a delimiter is found
if (pos >= 0)
{
// store the field
sBuffer = sWorkString.Left(pos);
// delete the field and the found delimiter
sWorkString = sWorkString.Mid(pos + 1);
}
// otherwise, if a delimiter isn't found
else
{
// the rest of the string is a field
sBuffer = sWorkString;
// and make the string empty
sWorkString.Empty();
}
// add the field to the CStringArray
m_aStrings.Add(sBuffer);
// increment the counter
m_nCount++;
}
return m_nCount;
}
//------------------------------------------------------------------------------
// NAME: CStringParser::ParseStringWithQuoter()
//
// PURPOSE: Separates the fields out of a copy of the original string by
// searching for the specified delimiter character. As the string
// is searched, it becomes shorter by deleting the most recently
// found field (and the next delimiter, if one exists) from the
// beginning of itself.
//
// This version of ParseString handles a quoted string. A quoted
// string may have the specified delimiter in an embedded between
// quote characters, and this instance of the delimiter must be
// ignored.
//
// PARMETERS: None
//
// RETURNS: int The number of fields found in the original string.
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 01/20/2001 jms Added this function.
//------------------------------------------------------------------------------
int CStringParser::ParseStringWithQuoter()
{
// get a copy of the string
CString sWorkString = GetOriginalString();
CString sBuffer;
int pos = 0;
m_nCount = 0;
// while the string is not empty...
while (!sWorkString.IsEmpty())
{
// find the position of the next delimiter
pos = sWorkString.Find(m_cDelimiter);
// if a delimiter is found
if (pos >= 0)
{
// if the first character is the specified quoter
if (sWorkString.GetAt(0) == m_cQuoter)
{
// we have work to do
sBuffer.Empty();
int nLength = 0;
BOOL bDone = FALSE;
do
{
//add the next character
sBuffer += CString(sWorkString.GetAt(nLength));
nLength++;
// if string is longer than one char and both ends are the quote char
if (nLength > 1 && sBuffer.GetAt(nLength - 1) == m_cQuoter)
{
// we are done
bDone = TRUE;
}
} while (!bDone);
// adjust our work string
sWorkString = sWorkString.Mid(nLength + 1);
}
else
{
sBuffer = sWorkString.Left(pos);
sWorkString = sWorkString.Mid(pos + 1);
}
}
// otherwise, if a delimiter isn't found
else
{
// the rest of the string is a field
sBuffer = sWorkString;
// and make the string empty
sWorkString.Empty();
}
// add the field to the CStringArray
m_aStrings.Add(sBuffer);
// increment the counter
m_nCount++;
}
return m_nCount;
}
//------------------------------------------------------------------------------
// NAME: CStringParser::FindExact()
//
// PURPOSE: Searches the entire array (excluding item 0) for an exact match
// of the specified string.
//
// PARMETERS: CString sText The string we're looking for
// int& nElement The element number of the found string
// or SP_NOTFOUND if not found.
// BOOL bCaseSensitive Case sensitivity matters
//
// RETURNS: CString The matching string if any.
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// ---------- ---- -----------------------------------------------------------
// 01/12/2001 jms Added function.
//------------------------------------------------------------------------------
CString CStringParser::FindExact(CString sText, int* nElement, BOOL bCaseSensitive/*=FALSE*/)
{
if (!bCaseSensitive)
{
sText.MakeUpper();
}
*nElement = SP_NOTFOUND;
CString sResult = "";
BOOL bFound = FALSE;
for (int i = 1; i <= m_nCount; i++)
{
sResult = m_aStrings.GetAt(i);
if (!bCaseSensitive)
{
sResult.MakeUpper();
}
if (sResult == sText)
{
*nElement = i;
sResult = m_aStrings.GetAt(i);
bFound = TRUE;
break;
}
sResult.Empty();
}
return sResult;
}
//------------------------------------------------------------------------------
// NAME: CStringParser::Find()
//
// PURPOSE: Searches the entire array (excluding item 0) for any string that
// contains the specified string.
//
// PARMETERS: CString sText The string we're looking for
// int& nElement The element number of the found string
// or SP_NOTFOUND if not found.
// BOOL bCaseSensitive Case sensitivity matters
//
// RETURNS: CString The matching string if any.
//
// CHANGE LOG:
// DATE INIT DESCRIPTION
// -------- ---- -------------------------------------------------------------
// 01/12/01 jms Added function.
//------------------------------------------------------------------------------
CString CStringParser::Find(CString sText, int* nElement, BOOL bCaseSensitive/*=FALSE*/)
{
if (!bCaseSensitive)
{
sText.MakeUpper();
}
*nElement = SP_NOTFOUND;
CString sResult = "";
BOOL bFound = FALSE;
for (int i = 1; i <= m_nCount; i++)
{
sResult = m_aStrings.GetAt(i);
if (!bCaseSensitive)
{
sResult.MakeUpper();
}
if (sResult.Find(sText) >= 0)
{
//save the position at which we found the string
*nElement = i;
// get it again (so we can get it in it's native form)
sResult = m_aStrings.GetAt(i);
bFound = TRUE;
break;
}
sResult.Empty();
}
return sResult;
}