Fast splitting of CString objects
Splitting CString objects is mostly easy, but can be tricky. I developed this function for using it with CSV files.
Introduction
Splitting CString
objects is mostly easy. But in some special cases, like handling CSV data, the following function can do a good job: it explains how to handle strings that contain the separator itself in the text.
The solution is to 'escape' all separators that occur in the text itself and use a splitting function that is aware of this 'escape' (chMagic
) character. The following function extends AfxGetSubString
with this behaviour and is optimized to be as fast as possible while using CString
.
The extracted CString
substring is directly manipulated using the GetBufferSetLength
member function.
Code
// Get substring, chMagic is a character which // makes chSep act as a normal character. // Return TRUE on success. inline BOOL GetSubString(CString& strSub, LPCTSTR lpszFullString, int iFullStringLen, int iSubString, TCHAR chSep, TCHAR chMagic) { int iPos, iPosOrig, iStartPos, iEndPos, iNumMagics; TCHAR* pcSubString; if((lpszFullString == NULL) || (iFullStringLen == 0)) return FALSE; // Find substring begin for(iStartPos = 0; (iStartPos < iFullStringLen) && (iSubString > 0); iStartPos++) { // May be separator ? if(*(lpszFullString + iStartPos) == chSep) { if(((iStartPos > 0) && (*(lpszFullString + iStartPos - 1) != chMagic)) || (iStartPos == 0)) { // Sure it is a separator! iSubString--; } } } // Return empty string when nothing found if(iSubString > 0) { strSub.Empty(); return FALSE; } // Find substring end iNumMagics = 0; for(iEndPos = iStartPos; iEndPos < iFullStringLen; iEndPos++) { // Count magics if(*(lpszFullString + iEndPos) == chMagic) { iNumMagics++; } // May be separator ? if(*(lpszFullString + iEndPos) == chSep) { if(((iEndPos > 0) && (*(lpszFullString + iEndPos - 1) != chMagic)) || (iEndPos == 0)) { // Sure it is the end break; } } } // Copy substring pcSubString = strSub.GetBufferSetLength( iEndPos - iStartPos - iNumMagics); iPosOrig = iStartPos; iEndPos -= iStartPos; if(pcSubString != NULL) { for(iPos = 0; iPos < iEndPos; iPos += sizeof(TCHAR)) { if(*(lpszFullString + iPosOrig) != chMagic) { *(pcSubString + iPos) = *(lpszFullString + iPosOrig); } else { iPos -= sizeof(TCHAR); iEndPos -= sizeof(TCHAR); } iPosOrig += sizeof(TCHAR); } *(pcSubString + iPos) = 0; return TRUE; } return FALSE; };
Example
CString strSub, strLine("1,2,3\\,1,4,..."); int iLen = strLine.GetLength(); GetSubString(strSub, strLine, iLen, 0, ',', '\\'); // strSub: 1 GetSubString(strSub, strLine, iLen, 1, ',', '\\'); // strSub: 2 GetSubString(strSub, strLine, iLen, 2, ',', '\\'); // strSub: 3,1