📄 atlmisc.h
字号:
CString dest;
AllocCopy(dest, nCount, 0, 0);
return dest;
}
CString Right(int nCount) const
{
if (nCount < 0)
nCount = 0;
else if (nCount > GetData()->nDataLength)
nCount = GetData()->nDataLength;
CString dest;
AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
return dest;
}
CString SpanIncluding(LPCTSTR lpszCharSet) const // strspn equivalent
{
ATLASSERT(_IsValidString(lpszCharSet));
return Left(_cstrspn(m_pchData, lpszCharSet));
}
CString SpanExcluding(LPCTSTR lpszCharSet) const // strcspn equivalent
{
ATLASSERT(_IsValidString(lpszCharSet));
return Left(_cstrcspn(m_pchData, lpszCharSet));
}
// upper/lower/reverse conversion
void MakeUpper()
{
CopyBeforeWrite();
CharUpper(m_pchData);
}
void MakeLower()
{
CopyBeforeWrite();
CharLower(m_pchData);
}
void MakeReverse()
{
CopyBeforeWrite();
_cstrrev(m_pchData);
}
// trimming whitespace (either side)
void TrimRight()
{
CopyBeforeWrite();
// find beginning of trailing spaces by starting at beginning (DBCS aware)
LPTSTR lpsz = m_pchData;
LPTSTR lpszLast = NULL;
while (*lpsz != _T('\0'))
{
if (_cstrisspace(*lpsz))
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
{
lpszLast = NULL;
}
lpsz = ::CharNext(lpsz);
}
if (lpszLast != NULL)
{
// truncate at trailing space start
*lpszLast = _T('\0');
GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);
}
}
void TrimLeft()
{
CopyBeforeWrite();
// find first non-space character
LPCTSTR lpsz = m_pchData;
while (_cstrisspace(*lpsz))
lpsz = ::CharNext(lpsz);
// fix up data and length
int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
GetData()->nDataLength = nDataLength;
}
// remove continuous occurrences of chTarget starting from right
void TrimRight(TCHAR chTarget)
{
// find beginning of trailing matches
// by starting at beginning (DBCS aware)
CopyBeforeWrite();
LPTSTR lpsz = m_pchData;
LPTSTR lpszLast = NULL;
while (*lpsz != _T('\0'))
{
if (*lpsz == chTarget)
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
lpszLast = NULL;
lpsz = ::CharNext(lpsz);
}
if (lpszLast != NULL)
{
// truncate at left-most matching character
*lpszLast = _T('\0');
GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);
}
}
// remove continuous occcurrences of characters in passed string, starting from right
void TrimRight(LPCTSTR lpszTargetList)
{
// find beginning of trailing matches by starting at beginning (DBCS aware)
CopyBeforeWrite();
LPTSTR lpsz = m_pchData;
LPTSTR lpszLast = NULL;
while (*lpsz != _T('\0'))
{
TCHAR* pNext = ::CharNext(lpsz);
if(pNext > lpsz + 1)
{
if (_cstrchr_db(lpszTargetList, *lpsz, *(lpsz + 1)) != NULL)
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
{
lpszLast = NULL;
}
}
else
{
if (_cstrchr(lpszTargetList, *lpsz) != NULL)
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
{
lpszLast = NULL;
}
}
lpsz = pNext;
}
if (lpszLast != NULL)
{
// truncate at left-most matching character
*lpszLast = _T('\0');
GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);
}
}
// remove continuous occurrences of chTarget starting from left
void TrimLeft(TCHAR chTarget)
{
// find first non-matching character
CopyBeforeWrite();
LPCTSTR lpsz = m_pchData;
while (chTarget == *lpsz)
lpsz = ::CharNext(lpsz);
if (lpsz != m_pchData)
{
// fix up data and length
int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
GetData()->nDataLength = nDataLength;
}
}
// remove continuous occcurrences of characters in passed string, starting from left
void TrimLeft(LPCTSTR lpszTargets)
{
// if we're not trimming anything, we're not doing any work
if (SafeStrlen(lpszTargets) == 0)
return;
CopyBeforeWrite();
LPCTSTR lpsz = m_pchData;
while (*lpsz != _T('\0'))
{
TCHAR* pNext = ::CharNext(lpsz);
if(pNext > lpsz + 1)
{
if (_cstrchr_db(lpszTargets, *lpsz, *(lpsz + 1)) == NULL)
break;
}
else
{
if (_cstrchr(lpszTargets, *lpsz) == NULL)
break;
}
lpsz = pNext;
}
if (lpsz != m_pchData)
{
// fix up data and length
int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);
SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));
GetData()->nDataLength = nDataLength;
}
}
// advanced manipulation
// replace occurrences of chOld with chNew
int Replace(TCHAR chOld, TCHAR chNew)
{
int nCount = 0;
// short-circuit the nop case
if (chOld != chNew)
{
// otherwise modify each character that matches in the string
CopyBeforeWrite();
LPTSTR psz = m_pchData;
LPTSTR pszEnd = psz + GetData()->nDataLength;
while (psz < pszEnd)
{
// replace instances of the specified character only
if (*psz == chOld)
{
*psz = chNew;
nCount++;
}
psz = ::CharNext(psz);
}
}
return nCount;
}
// replace occurrences of substring lpszOld with lpszNew;
// empty lpszNew removes instances of lpszOld
int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
{
// can't have empty or NULL lpszOld
int nSourceLen = SafeStrlen(lpszOld);
if (nSourceLen == 0)
return 0;
int nReplacementLen = SafeStrlen(lpszNew);
// loop once to figure out the size of the result string
int nCount = 0;
LPTSTR lpszStart = m_pchData;
LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
LPTSTR lpszTarget = NULL;
while (lpszStart < lpszEnd)
{
while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL)
{
nCount++;
lpszStart = lpszTarget + nSourceLen;
}
lpszStart += lstrlen(lpszStart) + 1;
}
// if any changes were made, make them
if (nCount > 0)
{
CopyBeforeWrite();
// if the buffer is too small, just allocate a new buffer (slow but sure)
int nOldLength = GetData()->nDataLength;
int nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount;
if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
{
CStringData* pOldData = GetData();
LPTSTR pstr = m_pchData;
if(!AllocBuffer(nNewLength))
return -1;
SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, pOldData->nDataLength * sizeof(TCHAR));
CString::Release(pOldData);
}
// else, we just do it in-place
lpszStart = m_pchData;
lpszEnd = m_pchData + GetData()->nDataLength;
// loop again to actually do the work
while (lpszStart < lpszEnd)
{
while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL)
{
int nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen);
int cchBuffLen = GetData()->nAllocLength - (int)(DWORD_PTR)(lpszTarget - m_pchData);
SecureHelper::memmove_x(lpszTarget + nReplacementLen, (cchBuffLen - nReplacementLen + 1) * sizeof(TCHAR), lpszTarget + nSourceLen, nBalance * sizeof(TCHAR));
SecureHelper::memcpy_x(lpszTarget, (cchBuffLen + 1) * sizeof(TCHAR), lpszNew, nReplacementLen * sizeof(TCHAR));
lpszStart = lpszTarget + nReplacementLen;
lpszStart[nBalance] = _T('\0');
nOldLength += (nReplacementLen - nSourceLen);
}
lpszStart += lstrlen(lpszStart) + 1;
}
ATLASSERT(m_pchData[nNewLength] == _T('\0'));
GetData()->nDataLength = nNewLength;
}
return nCount;
}
// remove occurrences of chRemove
int Remove(TCHAR chRemove)
{
CopyBeforeWrite();
LPTSTR pstrSource = m_pchData;
LPTSTR pstrDest = m_pchData;
LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
while (pstrSource < pstrEnd)
{
if (*pstrSource != chRemove)
{
*pstrDest = *pstrSource;
pstrDest = ::CharNext(pstrDest);
}
pstrSource = ::CharNext(pstrSource);
}
*pstrDest = _T('\0');
int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest);
GetData()->nDataLength -= nCount;
return nCount;
}
// insert character at zero-based index; concatenates if index is past end of string
int Insert(int nIndex, TCHAR ch)
{
CopyBeforeWrite();
if (nIndex < 0)
nIndex = 0;
int nNewLength = GetData()->nDataLength;
if (nIndex > nNewLength)
nIndex = nNewLength;
nNewLength++;
if (GetData()->nAllocLength < nNewLength)
{
CStringData* pOldData = GetData();
LPTSTR pstr = m_pchData;
if(!AllocBuffer(nNewLength))
return -1;
SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
CString::Release(pOldData);
}
// move existing bytes down
SecureHelper::memmove_x(m_pchData + nIndex + 1, (GetData()->nAllocLength - nIndex) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR));
m_pchData[nIndex] = ch;
GetData()->nDataLength = nNewLength;
return nNewLength;
}
// insert substring at zero-based index; concatenates if index is past end of string
int Insert(int nIndex, LPCTSTR pstr)
{
if (nIndex < 0)
nIndex = 0;
int nInsertLength = SafeStrlen(pstr);
int nNewLength = GetData()->nDataLength;
if (nInsertLength > 0)
{
CopyBeforeWrite();
if (nIndex > nNewLength)
nIndex = nNewLength;
nNewLength += nInsertLength;
if (GetData()->nAllocLength < nNewLength)
{
CStringData* pOldData = GetData();
LPTSTR pstr = m_pchData;
if(!AllocBuffer(nNewLength))
return -1;
SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));
CString::Release(pOldData);
}
// move existing bytes down
SecureHelper::memmove_x(m_pchData + nIndex + nInsertLength, (GetData()->nAllocLength + 1 - nIndex - nInsertLength) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR));
SecureHelper::memcpy_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), pstr, nInsertLength * sizeof(TCHAR));
GetData()->nDataLength = nNewLength;
}
return nNewLength;
}
// delete nCount characters starting at zero-based index
int Delete(int nIndex, int nCount = 1)
{
if (nIndex < 0)
nIndex = 0;
int nLength = GetData()->nDataLength;
if (nCount > 0 && nIndex < nLength)
{
if((nIndex + nCount) > nLength)
nCount = nLength - nIndex;
CopyBeforeWrite();
int nBytesToCopy = nLength - (nIndex + nCount) + 1;
SecureHelper::memmove_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
nLength -= nCount;
GetData()->nDataLength = nLength;
}
return nLength;
}
// searching (return starting index, or -1 if not found)
// look for a single character match
int Find(TCHAR ch) const // like "C" strchr
{
return Find(ch, 0);
}
int ReverseFind(TCHAR ch) const
{
// find last single character
LPCTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch);
// return -1 if not found, distance from beginning otherwise
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
int Find(TCHAR ch, int nStart) const // starting at index
{
int nLength = GetData()->nDataLength;
if (nStart < 0 || nStart >= nLength)
return -1;
// find first single character
LPCTSTR lpsz = _cstrchr(m_pchData + nStart, (_TUCHAR)ch);
// return -1 if not found and index otherwise
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
int FindOneOf(LPCTSTR lpszCharSet) const
{
ATLASSERT(_IsValidString(lpszCharSet));
LPCTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
// look for a specific sub-string
// find a sub-string (like strstr)
int Find(LPCTSTR lpszSub) const // like "C" strstr
{
return Find(lpszSub, 0);
}
int Find(LPCTSTR lpszSub, int nStart) const // starting at index
{
ATLASSERT(_IsValidString(lpszSub));
int nLength = GetData()->nDataLength;
if (nStart < 0 || nStart > nLength)
return -1;
// find first matching substring
LPCTSTR lpsz = _cstrstr(m_pchData + nStart, lpszSub);
// return -1 for not found, distance from beginning otherwise
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
// Concatentation for non strings
CString& Append(int n)
{
const int cchBuff = 12;
TCHAR szBuffer[cchBuff] = { 0 };
SecureHelper::wsprintf_x(szBuffer, cchBuff, _T("%d"), n);
ConcatInPlace(SafeStrlen(szBuffer), szBuffer);
return *this;
}
// simple formatting
// formatting (using wsprintf style formatting)
BOOL __cdecl Format(LPCTSTR lpszFormat, ...)
{
ATLASSERT(_IsValidString(lpszFormat));
va_list argList;
va_start(argList, lpszFormat);
BOOL bRet = FormatV(lpszFormat, argList);
va_end(argList);
return bRet;
}
BOOL __cdecl Format(UINT nFormatID, ...)
{
CString strFormat;
BOOL bRet = strFormat.LoadString(nFormatID);
ATLASSERT(bRet != 0);
va_list argList;
va_start(argList, nFormatID);
bRet = FormatV(strFormat, argList);
va_end(argList);
return bRet;
}
BOOL FormatV(LPCTSTR lpszFormat, va_list argList)
{
ATLASSERT(_IsValidString(lpszFormat));
enum _FormatModifiers
{
FORCE_ANSI = 0x10000,
FORCE_UNICODE = 0x20000,
FORCE_INT64 = 0x40000
};
va_list argListSave = argList;
// make a guess at the maximum length of the resulting string
int nMaxLen = 0;
for (LPCTSTR lpsz = lpszFormat; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz))
{
// handle '%' character, but watch out for '%%'
if (*lpsz != _T('%') || *(lpsz = ::CharNext(lpsz)) == _T('%'))
{
nMaxLen += (int)(::CharNext(lpsz) - lpsz);
continue;
}
int nItemLen = 0;
// handle '%' character with format
int nWidth = 0;
for (; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz))
{
// check for valid flags
if (*lpsz == _T('#'))
nMaxLen += 2; // for '0x'
else if (*lpsz == _T('*'))
nWidth = va_arg(argList, int);
else if (*lpsz == _T('-') || *lpsz == _T('+') || *lpsz == _T('0') || *lpsz == _T(' '))
;
else // hit non-flag character
break;
}
// get width and skip it
if (nWidth == 0)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -