Click here to Skip to main content
15,886,518 members
Articles / Desktop Programming / MFC

String Parsing Class (supports quoted strings)

Rate me:
Please Sign up or sign in to vote.
3.89/5 (24 votes)
14 Mar 2002 199.2K   1.3K   44  
Parse strings with specified delimiter and specified quote character
//------------------------------------------------------------------------------
// 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:		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;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) Paddedwall Software
United States United States
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.

My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.

Comments and Discussions