原文:http://blog.csdn.net/benny5609/article/details/1926088

CString使用的是引用技术,可以共享数据(这个大家都知道),另外空的CStirng是指向一个固定的地址的(_afxInitData).

另外CStirng是有长度限制的2147483647(无符号int 的最大值).

数据格式

struct CStringData

{

 long nRefs; //引用记数

 int nDataLength; //字符使用长度

 int nAllocLength; //分配长度

 TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方

 //this+1 相当与是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址

};

基本和络通讯的数据包差不多

typedef struct tagAnsMarketData //统一的应答结构

{

 WORD wStkNum; //数目

 char iData[1]; //数据

}ANS_MARKET_DATA,*PANS_MARKET_DATA;

下面是代码了

#include <windows.h>

#include <assert.h>

#include <stdlib.h>

#include <malloc.h>

#include <tchar.h>

string.h

#ifndef __JONES__STRING__

#define __JONES__STRING__

struct CStringData

{

 long nRefs; //引用记数

 int nDataLength; //字符使用长度

 int nAllocLength; //分配长度

 TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方

 //this+1 相当与是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址

};

class CString

{

public:

 //构造函数

 CString();

 CString(const CString& stringSrc);

 CString(TCHAR ch, int nLength =1);

 CString(LPCTSTR lpsz); // CString(LPCSTR lpsz); ANSI下版本

       //CString(LPCWSTR lpsz);UNICODE下版本

 CString(LPCTSTR lpch, int nLength); //CString(LPCSTR lpch, int nLength);ANSI下版本

          //CString(LPCWSTR lpch, int nLength);//UNICODE下版本

 CString(const unsigned char* psz);

 ~CString();

 //CStringData的属性

 int GetLength() const; //得到字符长度

 int GetAllocLength() const; //得到分配的内存长度

 BOOL IsEmpty() const; //判断字符长度是否为0

 operator LPCTSTR() const; //类型转换

 void Empty(); //清空CStringData

 //操作符重载

 const CString& operator=(const CString& stringSrc);

 const CString& operator=(LPCTSTR lpsz);

 const CString& operator=(TCHAR ch);

 const CString& operator+=(const CString& string);

 const CString& operator+=(TCHAR ch);

 const CString& operator+=(LPCTSTR lpsz);

 TCHAR operator[](int nIndex) const;

friend CString operator+(const CString& string1,const CString& string2);

 friend CString operator+(const CString& string, TCHAR ch);

 friend CString operator+(TCHAR ch, const CString& string);

 friend CString operator+(const CString& string, LPCTSTR lpsz);

 friend CString operator+(LPCTSTR lpsz, const CString& string);

//操作,脱离共享数据块

 int Delete(int nIndex, int nCount = 1);//删除从nIndex开始长度为nCount的数据

 int Insert(int nIndex, TCHAR ch); //插入一个字符

 int Insert(int nIndex, LPCTSTR pstr); //插入一个字符串

 int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew); //替换数据

 int Replace(TCHAR chOld, TCHAR chNew); //替换数据

 int Remove(TCHAR chRemove); //移除一个字符

 void TrimRight(LPCTSTR lpszTargetList);

 void TrimRight(TCHAR chTarget);//去掉右边chTarget

 void TrimRight(); //去掉右边空格

 void TrimLeft(LPCTSTR lpszTargets);

 void TrimLeft(TCHAR chTarget); //去掉左边chTarget

 void TrimLeft(); //去掉左边空格

 //取某段字符串

 void SetAt(int nIndex, TCHAR ch);

 TCHAR GetAt(int nIndex) const;

 CString Mid(int nFirst) const; //取某段字符串

 CString Mid(int nFirst, int nCount) const; //取某段字符串

 CString Right(int nCount) const; //取右边字符串

 CString Left(int nCount) const; //取左边字符串

 void CString::MakeUpper(); //大写

 void CString::MakeLower(); //小写

 void CString::MakeReverse(); //????不知道干什么的 strrev

 //查找

 int Find(TCHAR ch) const;

 int Find(TCHAR ch, int nStart) const;

 int ReverseFind(TCHAR ch) const;

 int Find(LPCTSTR lpszSub) const;

 int Find(LPCTSTR lpszSub, int nStart) const;

 int FindOneOf(LPCTSTR lpszCharSet) const;//得到第一个匹配lpszCharSet中其中一个字符的位置 调用_tcspbrk

 //高级操作

 LPTSTR GetBuffer(int nMinBufLength); //重新分配内存,在拷贝原来的数据

 void ReleaseBuffer(int nNewLength=-1); //在[nNewLength]='/0',对内存大小没有改变

 LPTSTR GetBufferSetLength(int nNewLength); //重新分配内存,在拷贝原来的数据

 void FreeExtra(); //深拷贝自己,然后--原来的引用记数器

 LPTSTR LockBuffer(); //引用计数器=-1,加锁

 void UnlockBuffer(); //解锁,引用计数器=1

 //比较

 int Compare(LPCTSTR lpsz) const; //区分大小写比较

 int CompareNoCase(LPCTSTR lpsz) const; //不区分大小写比较

 //比较速度没有Compare快

 int Collate(LPCTSTR lpsz) const; //区分大小写比较

 int CollateNoCase(LPCTSTR lpsz) const; //不区分大小写比较

 //格式化字符串

 void Format(LPCTSTR lpszFormat, ...);//CSting中最长的函数了,完全是自己分析的(牛啊)

private:

 void Init();

 CStringData* GetData() const; //通过m_pchData-1 得到CStringData

 void AllocBuffer(int nLen); //给CStringData分配内存,不带记数器

 void CopyBeforeWrite(); //带引用记数的复制自己深拷贝

 void AllocBeforeWrite(int nLen); //给CStringData分配内存,带记数器

 void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);//分配内存,并拷贝lpszSrcData内容

 //把nCopyIndex开始的nCopyLen长度的数据拷贝给dest,nExtraLen扩充的长度,次函数好像没下面用

 void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,int nExtraLen) const;

 void Release(); //--引用记数器并判断是否删除内存,如删除并初始化

 void FormatV(LPCTSTR lpszFormat, va_list argList);//格式化字符串

 void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,

  int nSrc2Len, LPCTSTR lpszSrc2Data);//连接数据lpszSrc1Data+lpszSrc2Data

 void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData); //连接字符串

static void  Release(CStringData* pData); //--引用记数器并判断是否删除内存

 static void FreeData(CStringData* pData); //释放内存

 static int SafeStrlen(LPCTSTR lpsz); //得到长度

 LPTSTR m_pchData; //指向CStringData的数据区

};

/*调用CString::Compare比较大小,如果比较中有CStirng的话用

调用operator LPCTSTR()转化类型为LPCTSTR

*/

bool operator==(const CString& s1, const CString& s2);

bool operator==(const CString& s1, LPCTSTR s2);

bool operator==(LPCTSTR s1, const CString& s2);

bool operator!=(const CString& s1, const CString& s2);

bool operator!=(const CString& s1, LPCTSTR s2);

bool operator!=(LPCTSTR s1, const CString& s2);

bool operator<(const CString& s1, const CString& s2);

bool operator<(const CString& s1, LPCTSTR s2);

bool operator<(LPCTSTR s1, const CString& s2);

bool operator>(const CString& s1, const CString& s2);

bool operator>(const CString& s1, LPCTSTR s2);

bool operator>(LPCTSTR s1, const CString& s2);

bool operator<=(const CString& s1, const CString& s2);

bool operator<=(const CString& s1, LPCTSTR s2);

bool operator<=(LPCTSTR s1, const CString& s2);

bool operator>=(const CString& s1, const CString& s2);

bool operator>=(const CString& s1, LPCTSTR s2);

bool operator>=(LPCTSTR s1, const CString& s2);

//////////////////////////////////////////////////////////////////////

//检测lpsz是否有效,调用了IsBadStringPtr

BOOL AfxIsValidString(LPCTSTR lpsz, int nLength = -1);

//检测lp是否能读写权限,调用了IsBadReadPtr,IsBadStringPtr

BOOL AfxIsValidAddress(const void* lp,UINT nBytes, BOOL bReadWrite = TRUE);

//CStirng数组操作

void ConstructElements(CString* pElements, int nCount); //初始化CStirng数组

void DestructElements(CString* pElements, int nCount); //删除CStirng数组

void CopyElements(CString* pDest, const CString* pSrc, int nCount); //CString数组拷贝

#endif

string.cpp

#include "stdafx.h"

#include "string.h"

TCHAR afxChNil = '/0';

int _afxInitData[] = { -1, 0, 0, 0 }; //初始化CStringData的地址

CStringData* _afxDataNil = (CStringData*)&_afxInitData; //地址转化为CStringData*

LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));

const CString&  AfxGetEmptyString()  //建立一个空的CString

{ return *(CString*)&_afxPchNil; }

BOOL AfxIsValidString(LPCTSTR lpsz, int nLength /* = -1 */)

{

 if (lpsz == NULL)

  return FALSE;

 return ::IsBadStringPtr(lpsz, nLength) == 0;

}

BOOL AfxIsValidAddress(const void* lp, UINT nBytes,BOOL bReadWrite /* = TRUE */)

{

 return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&

  (!bReadWrite !IsBadWritePtr((LPVOID)lp, nBytes)));

}

void CString::Init()

{ m_pchData=AfxGetEmptyString().m_pchData; }

CString::CString()

{ Init(); }

int CString::GetLength() const

{ return GetData()->nDataLength; }

int CString::GetAllocLength() const

{ return GetData()->nAllocLength; }

BOOL CString::IsEmpty() const

{ return GetData()->nDataLength == 0; }

CStringData* CString::GetData() const

{

 assert(m_pchData != NULL);

 return ((CStringData*)m_pchData)-1;

}

CString::operator LPCTSTR() const

{ return m_pchData; }

int CString::SafeStrlen(LPCTSTR lpsz)

{ return (lpsz == NULL) ? 0 : lstrlen(lpsz); }

void CString::AllocBuffer(int nLen)

{

 assert(nLen >= 0);

 assert(nLen <= 2147483647-1);    // (signed) int 的最大值

if (nLen == 0)

  Init();

 else

 {

  CStringData* pData;

  {

   pData = (CStringData*)

    new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];

   pData->nAllocLength = nLen;

  }

  pData->nRefs = 1;

  pData->data()[nLen] = '/0';

  pData->nDataLength = nLen;

  m_pchData = pData->data();

 }

}

void CString::FreeData(CStringData* pData)

{

 delete[] (BYTE*)pData;

}

void CString::CopyBeforeWrite()

{

 if (GetData()->nRefs > 1)

 {

  CStringData* pData = GetData();

  Release();

  AllocBuffer(pData->nDataLength);

  memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));

 }

 assert(GetData()->nRefs <= 1);

}

void CString::AllocBeforeWrite(int nLen)

{

 if (GetData()->nRefs > 1 nLen > GetData()->nAllocLength)

 {

  Release();

  AllocBuffer(nLen);

 }

 assert(GetData()->nRefs <= 1);

}

void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)

{

 AllocBeforeWrite(nSrcLen);

 memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));

 GetData()->nDataLength = nSrcLen;

 m_pchData[nSrcLen] = '/0';

}

void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,

  int nExtraLen) const

{

 int nNewLen = nCopyLen + nExtraLen;

 if (nNewLen == 0)

 {

  dest.Init();

 }

 else

 {

  dest.AllocBuffer(nNewLen);

  memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));

 }

}

CString::~CString()

{

 if (GetData() != _afxDataNil)

 {

  if (InterlockedDecrement(&GetData()->nRefs) <= 0)

   FreeData(GetData());

 }

}

CString::CString(const CString& stringSrc)

{

 assert(stringSrc.GetData()->nRefs != 0);

 if (stringSrc.GetData()->nRefs >= 0)

 {

  assert(stringSrc.GetData() != _afxDataNil);

  m_pchData = stringSrc.m_pchData;

  InterlockedIncrement(&GetData()->nRefs);

 }

 else

 {

  Init();

  *this = stringSrc.m_pchData;

 }

}

CString::CString(LPCTSTR lpsz)

{

 Init();

 int nLen = SafeStrlen(lpsz);

 if (nLen != 0)

 {

  AllocBuffer(nLen);

  memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));

 }

}

CString::CString(LPCTSTR lpch, int nLength)

{

 Init();

 if (nLength != 0)

 {

  assert(AfxIsValidAddress(lpch, nLength, FALSE));

  AllocBuffer(nLength);

  memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));

 }

}

void CString::Release()

{

 if (GetData() != _afxDataNil)

 {

  assert(GetData()->nRefs != 0);

  if (InterlockedDecrement(&GetData()->nRefs) <= 0)

   FreeData(GetData());

  Init();

 }

}

void CString::Release(CStringData* pData)

{

 if (pData != _afxDataNil)

 {

  assert(pData->nRefs != 0);

  if (InterlockedDecrement(&pData->nRefs) <= 0)

   FreeData(pData);

 }

}

void CString::Empty()

{

 if (GetData()->nDataLength == 0)

  return;

 if (GetData()->nRefs >= 0)

  Release();

 else

  *this = &afxChNil;

 assert(GetData()->nDataLength == 0);

 assert(GetData()->nRefs < 0 GetData()->nAllocLength == 0);

}

const CString& CString::operator=(const CString& stringSrc)

{

 if (m_pchData != stringSrc.m_pchData)

 {

  if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) 

   stringSrc.GetData()->nRefs < 0)

  {

   //新建一快数据

   AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);

  }

  else

  {

   //只拷贝指针

   Release();

   assert(stringSrc.GetData() != _afxDataNil);

   m_pchData = stringSrc.m_pchData;

   InterlockedIncrement(&GetData()->nRefs);

  }

 }

 return *this;

}

const CString& CString::operator=(LPCTSTR lpsz)

{

 assert(lpsz == NULL AfxIsValidString(lpsz));

 AssignCopy(SafeStrlen(lpsz), lpsz);

 return *this;

}

const CString& CString::operator=(TCHAR ch)

{

 AssignCopy(1, &ch);

 return *this;

}

int CString::Delete(int nIndex, int nCount /* = 1 */)

{

 if (nIndex < 0)

  nIndex = 0;

 int nNewLength = GetData()->nDataLength;

 if (nCount > 0 && nIndex < nNewLength)

 {

  CopyBeforeWrite(); //脱离共享数据块,

  int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;

  //移动数据

  memcpy(m_pchData + nIndex,

   m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));

  GetData()->nDataLength = nNewLength - nCount;

 }

 return nNewLength;

}

int CString::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;

  AllocBuffer(nNewLength);

  memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));

  CString::Release(pOldData);

 }

 //插入数据

 memcpy(m_pchData + nIndex + 1,

  m_pchData + nIndex, (nNewLength-nIndex)*sizeof(TCHAR));

 m_pchData[nIndex] = ch;

 GetData()->nDataLength = nNewLength;

return nNewLength;

}

int CString::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;

   AllocBuffer(nNewLength);

   memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));

   CString::Release(pOldData);

  }

//移动数据,留出插入的位move也可以

  memcpy(m_pchData + nIndex + nInsertLength,

   m_pchData + nIndex,

   (nNewLength-nIndex-nInsertLength+1)*sizeof(TCHAR));

  //插入数据

  memcpy(m_pchData + nIndex,

   pstr, nInsertLength*sizeof(TCHAR));

  GetData()->nDataLength = nNewLength;

 }

return nNewLength;

}

int CString::Replace(TCHAR chOld, TCHAR chNew)

{

 int nCount = 0;

 if (chOld != chNew) //替换的不能相同

 {

  CopyBeforeWrite();

  LPTSTR psz = m_pchData;

  LPTSTR pszEnd = psz + GetData()->nDataLength;

  while (psz < pszEnd)

  {

   if (*psz == chOld) //替换

   {

    *psz = chNew;

    nCount++;

   }

   psz = _tcsinc(psz); //相当于++psz,考虑要UNICODE下版本才用的

  }

 }

 return nCount;

}

int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)

{

 int nSourceLen = SafeStrlen(lpszOld);

 if (nSourceLen == 0) //要替换的不能为空

  return 0;

 int nReplacementLen = SafeStrlen(lpszNew);

int nCount = 0;

 LPTSTR lpszStart = m_pchData;

 LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;

 LPTSTR lpszTarget;

 while (lpszStart < lpszEnd) //检索要替换的个数

 {

  while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)

  {

   nCount++;

   lpszStart = lpszTarget + nSourceLen;

  }

  lpszStart += lstrlen(lpszStart) + 1;

 }

if (nCount > 0)

 {

  CopyBeforeWrite();

  int nOldLength = GetData()->nDataLength;

  int nNewLength =  nOldLength + (nReplacementLen-nSourceLen)*nCount; //替换以后的长度

  if (GetData()->nAllocLength < nNewLength GetData()->nRefs > 1)

  { //超出原来的内存长度动态分配

   CStringData* pOldData = GetData();

   LPTSTR pstr = m_pchData;

   AllocBuffer(nNewLength);

   memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));

   CString::Release(pOldData);

  }

  

  lpszStart = m_pchData;

  lpszEnd = m_pchData + GetData()->nDataLength;

while (lpszStart < lpszEnd) //这个循环好象没什么用

  {

   while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL) //开始替换

   {

    int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen); //要往后移的长度

    //移动数据,留出插入的位

    memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,

     nBalance * sizeof(TCHAR));

    //插入替换数据

    memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));

    lpszStart = lpszTarget + nReplacementLen;

    lpszStart[nBalance] = '/0';

    nOldLength += (nReplacementLen - nSourceLen); //现有数据长度

   }

   lpszStart += lstrlen(lpszStart) + 1;

  }

  assert(m_pchData[nNewLength] == '/0');

  GetData()->nDataLength = nNewLength;

 }

return nCount;

}

int CString::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 = _tcsinc(pstrDest);

  }

  pstrSource = _tcsinc(pstrSource);//++pstrSource

 }

 *pstrDest = '/0';

 int nCount = pstrSource - pstrDest; //比较变态的计算替换个数,

 GetData()->nDataLength -= nCount;

return nCount;

}

CString CString::Mid(int nFirst) const

{

 return Mid(nFirst, GetData()->nDataLength - nFirst);

}

CString CString::Mid(int nFirst, int nCount) const

{

 if (nFirst < 0)

  nFirst = 0;

 if (nCount < 0)

  nCount = 0;

if (nFirst + nCount > GetData()->nDataLength)

  nCount = GetData()->nDataLength - nFirst;

 if (nFirst > GetData()->nDataLength)

  nCount = 0;

assert(nFirst >= 0);

 assert(nFirst + nCount <= GetData()->nDataLength);

//取去整个数据

 if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)

  return *this;

 

 CString dest; 

 AllocCopy(dest, nCount, nFirst, 0);

 return dest;

}

CString CString::Right(int nCount) const

{

 if (nCount < 0)

  nCount = 0;

 if (nCount >= GetData()->nDataLength)

  return *this;

CString dest;

 AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);

 return dest;

}

CString CString::Left(int nCount) const

{

 if (nCount < 0)

  nCount = 0;

 if (nCount >= GetData()->nDataLength)

  return *this;

CString dest;

 AllocCopy(dest, nCount, 0, 0);

 return dest;

}

int CString::ReverseFind(TCHAR ch) const

{

 //从最后查找

 LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);

 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);

}

int CString::Find(TCHAR ch) const

{

 return Find(ch, 0);

}

int CString::Find(TCHAR ch, int nStart) const

{

 int nLength = GetData()->nDataLength;

 if (nStart >= nLength)

  return -1;

LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);

 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);

}

int CString::Find(LPCTSTR lpszSub) const

{

 return Find(lpszSub, 0);

}

int CString::Find(LPCTSTR lpszSub, int nStart) const

{

 assert(AfxIsValidString(lpszSub));

int nLength = GetData()->nDataLength;

 if (nStart > nLength)

  return -1;

LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);

return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);

}

int CString::FindOneOf(LPCTSTR lpszCharSet) const

{

 assert(AfxIsValidString(lpszCharSet));

 LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);

 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);

}

void CString::MakeUpper()

{

 CopyBeforeWrite();

 _tcsupr(m_pchData);

}

void CString::MakeLower()

{

 CopyBeforeWrite();

 _tcslwr(m_pchData);

}

void CString::MakeReverse()

{

 CopyBeforeWrite();

 _tcsrev(m_pchData);

}

void CString::SetAt(int nIndex, TCHAR ch)

{

 assert(nIndex >= 0);

 assert(nIndex < GetData()->nDataLength);

CopyBeforeWrite();

 m_pchData[nIndex] = ch;

}

void CString::TrimRight(LPCTSTR lpszTargetList)

{

 CopyBeforeWrite();

 LPTSTR lpsz = m_pchData;

 LPTSTR lpszLast = NULL;

while (*lpsz != '/0')

 {

  if (_tcschr(lpszTargetList, *lpsz) != NULL)

  {

   if (lpszLast == NULL)

    lpszLast = lpsz;

  }

  else

   lpszLast = NULL;

  lpsz = _tcsinc(lpsz);

 }

if (lpszLast != NULL)

 {

  *lpszLast = '/0';

  GetData()->nDataLength = lpszLast - m_pchData;

 }

}

void CString::TrimRight(TCHAR chTarget)

{

 CopyBeforeWrite();

 LPTSTR lpsz = m_pchData;

 LPTSTR lpszLast = NULL;

while (*lpsz != '/0')

 {

  if (*lpsz == chTarget)

  {

   if (lpszLast == NULL)

    lpszLast = lpsz;

  }

  else

   lpszLast = NULL;

  lpsz = _tcsinc(lpsz);

 }

if (lpszLast != NULL)

 {

  *lpszLast = '/0';

  GetData()->nDataLength = lpszLast - m_pchData;

 }

}

void CString::TrimRight()

{

 CopyBeforeWrite();

 LPTSTR lpsz = m_pchData;

 LPTSTR lpszLast = NULL;

while (*lpsz != '/0')

 {

  if (_istspace(*lpsz))

  {

   if (lpszLast == NULL)

    lpszLast = lpsz;

  }

  else

   lpszLast = NULL;

  lpsz = _tcsinc(lpsz);

 }

if (lpszLast != NULL)

 {

  // truncate at trailing space start

  *lpszLast = '/0';

  GetData()->nDataLength = lpszLast - m_pchData;

 }

}

void CString::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 != '/0')

 {

  if (_tcschr(lpszTargets, *lpsz) == NULL)

   break;

  lpsz = _tcsinc(lpsz);

 }

if (lpsz != m_pchData)

 {

  // fix up data and length

  int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);

  memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));

  GetData()->nDataLength = nDataLength;

 }

}

void CString::TrimLeft(TCHAR chTarget)

{

 CopyBeforeWrite();

 LPCTSTR lpsz = m_pchData;

while (chTarget == *lpsz)

  lpsz = _tcsinc(lpsz);

if (lpsz != m_pchData)

 {

  int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);

  memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));

  GetData()->nDataLength = nDataLength;

 }

}

void CString::TrimLeft()

{

 CopyBeforeWrite();

 LPCTSTR lpsz = m_pchData;

while (_istspace(*lpsz))

  lpsz = _tcsinc(lpsz);

if (lpsz != m_pchData)

 {

  int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);

  memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));

  GetData()->nDataLength = nDataLength;

 }

}

#define TCHAR_ARG   TCHAR

#define WCHAR_ARG   WCHAR

#define CHAR_ARG    char

struct _AFX_DOUBLE  { BYTE doubleBits[sizeof(double)]; };

#ifdef _X86_

 #define DOUBLE_ARG  _AFX_DOUBLE

#else

 #define DOUBLE_ARG  double

#endif

#define FORCE_ANSI      0x10000

#define FORCE_UNICODE   0x20000

#define FORCE_INT64     0x40000

void CString::FormatV(LPCTSTR lpszFormat, va_list argList)

{

 assert(AfxIsValidString(lpszFormat));

va_list argListSave = argList;

// make a guess at the maximum length of the resulting string

 int nMaxLen = 0;

 for (LPCTSTR lpsz = lpszFormat; *lpsz != '/0'; lpsz = _tcsinc(lpsz))

 {

  //查找%,对%%不在查找范围

  if (*lpsz != '%' *(lpsz = _tcsinc(lpsz)) == '%')

  {

   nMaxLen += _tclen(lpsz);

   continue;

  }

int nItemLen = 0;

//%后面的格式判断

  int nWidth = 0;

  for (; *lpsz != '/0'; lpsz = _tcsinc(lpsz))

  {

   if (*lpsz == '#') 

    nMaxLen += 2;   // 16进制 '0x'

   else if (*lpsz == '*')

    nWidth = va_arg(argList, int);

   else if (*lpsz == '-' *lpsz == '+' *lpsz == '0' 

    *lpsz == ' ')

    ;

   else // hit non-flag character

    break;

  }

  // get width and skip it

  if (nWidth == 0)

  {

   // width indicated by

   nWidth = _ttoi(lpsz);

   for (; *lpsz != '/0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))

    ;

  }

  assert(nWidth >= 0);

int nPrecision = 0;

  if (*lpsz == '.')

  {

   // skip past '.' separator (width.precision)

   lpsz = _tcsinc(lpsz);

// get precision and skip it

   if (*lpsz == '*')

   {

    nPrecision = va_arg(argList, int);

    lpsz = _tcsinc(lpsz);

   }

   else

   {

    nPrecision = _ttoi(lpsz);

    for (; *lpsz != '/0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))

     ;

   }

   assert(nPrecision >= 0);

  }

// should be on type modifier or specifier

  int nModifier = 0;

  if (_tcsncmp(lpsz, _T("I64"), 3) == 0)

  {

   lpsz += 3;

   nModifier = FORCE_INT64;

#if !defined(_X86_) && !defined(_ALPHA_)

   // __int64 is only available on X86 and ALPHA platforms

   ASSERT(FALSE);

#endif

  }

  else

  {

   switch (*lpsz)

   {

   // modifiers that affect size

   case 'h':

    nModifier = FORCE_ANSI;

    lpsz = _tcsinc(lpsz);

    break;

   case 'l':

    nModifier = FORCE_UNICODE;

    lpsz = _tcsinc(lpsz);

    break;

// modifiers that do not affect size

   case 'F':

   case 'N':

   case 'L':

    lpsz = _tcsinc(lpsz);

    break;

   }

  }

// now should be on specifier

  switch (*lpsz | nModifier)

  {

  // single characters

  case 'c':

  case 'C':

   nItemLen = 2;

   va_arg(argList, TCHAR_ARG);

   break;

  case 'c'|FORCE_ANSI:

  case 'C'|FORCE_ANSI:

   nItemLen = 2;

   va_arg(argList, CHAR_ARG);

   break;

  case 'c'|FORCE_UNICODE:

  case 'C'|FORCE_UNICODE:

   nItemLen = 2;

   va_arg(argList, WCHAR_ARG);

   break;

// strings

  case 's':

   {

    LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);

    if (pstrNextArg == NULL)

       nItemLen = 6;  // "(null)"

    else

    {

       nItemLen = lstrlen(pstrNextArg);

       nItemLen = max(1, nItemLen);

    }

   }

   break;

case 'S':

   {

#ifndef _UNICODE

    LPWSTR pstrNextArg = va_arg(argList, LPWSTR);

    if (pstrNextArg == NULL)

       nItemLen = 6;  // "(null)"

    else

    {

       nItemLen = wcslen(pstrNextArg);

       nItemLen = max(1, nItemLen);

    }

#else

    LPCSTR pstrNextArg = va_arg(argList, LPCSTR);

    if (pstrNextArg == NULL)

       nItemLen = 6; // "(null)"

    else

    {

       nItemLen = lstrlenA(pstrNextArg);

       nItemLen = max(1, nItemLen);

    }

#endif

   }

   break;

case 's'|FORCE_ANSI:

  case 'S'|FORCE_ANSI:

   {

    LPCSTR pstrNextArg = va_arg(argList, LPCSTR);

    if (pstrNextArg == NULL)

       nItemLen = 6; // "(null)"

    else

    {

       nItemLen = lstrlenA(pstrNextArg);

       nItemLen = max(1, nItemLen);

    }

   }

   break;

case 's'|FORCE_UNICODE:

  case 'S'|FORCE_UNICODE:

   {

    LPWSTR pstrNextArg = va_arg(argList, LPWSTR);

    if (pstrNextArg == NULL)

       nItemLen = 6; // "(null)"

    else

    {

       nItemLen = wcslen(pstrNextArg);

       nItemLen = max(1, nItemLen);

    }

   }

   break;

  }

// adjust nItemLen for strings

  if (nItemLen != 0)

  {

   if (nPrecision != 0)

    nItemLen = min(nItemLen, nPrecision);

   nItemLen = max(nItemLen, nWidth);

  }

  else

  {

   switch (*lpsz)

   {

   // integers

   case 'd':

   case 'i':

   case 'u':

   case 'x':

   case 'X':

   case 'o':

    if (nModifier & FORCE_INT64)

     va_arg(argList, __int64);

    else

     va_arg(argList, int);

    nItemLen = 32;

    nItemLen = max(nItemLen, nWidth+nPrecision);

    break;

case 'e':

   case 'g':

   case 'G':

    va_arg(argList, DOUBLE_ARG);

    nItemLen = 128;

    nItemLen = max(nItemLen, nWidth+nPrecision);

    break;

case 'f':

    {

     double f;

     LPTSTR pszTemp;

// 312 == strlen("-1+(309 zeroes).")

     // 309 zeroes == max precision of a double

     // 6 == adjustment in case precision is not specified,

     //   which means that the precision defaults to 6

     pszTemp = (LPTSTR)_alloca(max(nWidth, 312+nPrecision+6));

f = va_arg(argList, double);

     _stprintf( pszTemp, _T( "%*.*f" ), nWidth, nPrecision+6, f );

     nItemLen = _tcslen(pszTemp);

    }

    break;

case 'p':

    va_arg(argList, void*);

    nItemLen = 32;

    nItemLen = max(nItemLen, nWidth+nPrecision);

    break;

// no output

   case 'n':

    va_arg(argList, int*);

    break;

default:

    assert(FALSE);  // unknown formatting option

   }

  }

// adjust nMaxLen for output nItemLen

  nMaxLen += nItemLen;

 }

GetBuffer(nMaxLen);

 //VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());

 _vstprintf(m_pchData, lpszFormat, argListSave);

 ReleaseBuffer();

va_end(argListSave);

}

void CString::Format(LPCTSTR lpszFormat, ...)

{

 assert(AfxIsValidString(lpszFormat));

va_list argList;

 va_start(argList, lpszFormat);

 FormatV(lpszFormat, argList);

 va_end(argList);

}

void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,int nSrc2Len, LPCTSTR lpszSrc2Data)

{

 int nNewLen = nSrc1Len + nSrc2Len;

 if (nNewLen != 0)

 {

  AllocBuffer(nNewLen);

  memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));

  memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));

 }

}

void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)

{

 if (nSrcLen == 0)

  return;

 

 if (GetData()->nRefs > 1 GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)

 {//动态分配

  CStringData* pOldData = GetData();

  ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);

  assert(pOldData != NULL);

  CString::Release(pOldData);

 }

 else

 {//直接往后添加

  memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));

  GetData()->nDataLength += nSrcLen;

  assert(GetData()->nDataLength <= GetData()->nAllocLength);

  m_pchData[GetData()->nDataLength] = '/0';

 }

}

const CString& CString::operator+=(LPCTSTR lpsz)

{

 assert(lpsz == NULL AfxIsValidString(lpsz));

 ConcatInPlace(SafeStrlen(lpsz), lpsz);

 return *this;

}

const CString& CString::operator+=(TCHAR ch)

{

 ConcatInPlace(1, &ch);

 return *this;

}

const CString& CString::operator+=(const CString& string)

{

 ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);

 return *this;

}

LPTSTR CString::GetBuffer(int nMinBufLength)

{

 assert(nMinBufLength >= 0);

 if (GetData()->nRefs > 1 nMinBufLength > GetData()->nAllocLength)

 { //重新动态分配

  CStringData* pOldData = GetData();

  int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it

  if (nMinBufLength < nOldLen)

   nMinBufLength = nOldLen;

  AllocBuffer(nMinBufLength);

  memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));

  GetData()->nDataLength = nOldLen;

  CString::Release(pOldData);

 }

 assert(GetData()->nRefs <= 1);

 assert(m_pchData != NULL);

 return m_pchData;

}

void CString::ReleaseBuffer(int nNewLength)

{

 CopyBeforeWrite();  //脱离共享数据块,

if (nNewLength == -1)

  nNewLength = lstrlen(m_pchData); // zero terminated

assert(nNewLength <= GetData()->nAllocLength);

 GetData()->nDataLength = nNewLength;

 m_pchData[nNewLength] = '/0';

}

LPTSTR CString::GetBufferSetLength(int nNewLength)

{

 assert(nNewLength >= 0);

GetBuffer(nNewLength);

 GetData()->nDataLength = nNewLength;

 m_pchData[nNewLength] = '/0';

 return m_pchData;

}

void CString::FreeExtra()

{

 assert(GetData()->nDataLength <= GetData()->nAllocLength);

 if (GetData()->nDataLength != GetData()->nAllocLength)

 {

  CStringData* pOldData = GetData();

  AllocBuffer(GetData()->nDataLength);

  memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));

  assert(m_pchData[GetData()->nDataLength] == '/0');

  CString::Release(pOldData);

 }

 assert(GetData() != NULL);

}

LPTSTR CString::LockBuffer()

{

 LPTSTR lpsz = GetBuffer(0);

 GetData()->nRefs = -1;

 return lpsz;

}

void CString::UnlockBuffer()

{

 assert(GetData()->nRefs == -1);

 if (GetData() != _afxDataNil)

  GetData()->nRefs = 1;

}

int CString::Compare(LPCTSTR lpsz) const

{

 assert(AfxIsValidString(lpsz));

 return _tcscmp(m_pchData, lpsz);

}

int CString::CompareNoCase(LPCTSTR lpsz) const

{

 assert(AfxIsValidString(lpsz));

 return _tcsicmp(m_pchData, lpsz);



 

// CString::Collate is often slower than Compare but is MBSC/Unicode

//  aware as well as locale-sensitive with respect to sort order.

int CString::Collate(LPCTSTR lpsz) const

{

 assert(AfxIsValidString(lpsz));

 return _tcscoll(m_pchData, lpsz);

}

int CString::CollateNoCase(LPCTSTR lpsz) const

{

 assert(AfxIsValidString(lpsz));

 return _tcsicoll(m_pchData, lpsz);

}

TCHAR CString::GetAt(int nIndex) const

{

 assert(nIndex >= 0);

 assert(nIndex < GetData()->nDataLength);

 return m_pchData[nIndex];

}

TCHAR CString::operator[](int nIndex) const

{

 assert(nIndex >= 0);

 assert(nIndex < GetData()->nDataLength);

 return m_pchData[nIndex];

}

////////////////////////////////////////////////////////////////////////////////

CString operator+(const CString& string1, const CString& string2)

{

 CString s;

 s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,

  string2.GetData()->nDataLength, string2.m_pchData);

 return s;

}

CString operator+(const CString& string, LPCTSTR lpsz)

{

 assert(lpsz == NULL AfxIsValidString(lpsz));

 CString s;

 s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,

  CString::SafeStrlen(lpsz), lpsz);

 return s;

}

CString operator+(LPCTSTR lpsz, const CString& string)

{

 assert(lpsz == NULL AfxIsValidString(lpsz));

 CString s;

 s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,

  string.m_pchData);

 return s;

}

bool operator==(const CString& s1, const CString& s2)

{ return s1.Compare(s2) == 0; }

bool operator==(const CString& s1, LPCTSTR s2)

{ return s1.Compare(s2) == 0; }

bool operator==(LPCTSTR s1, const CString& s2)

{ return s2.Compare(s1) == 0; }

bool operator!=(const CString& s1, const CString& s2)

{ return s1.Compare(s2) != 0; }

bool operator!=(const CString& s1, LPCTSTR s2)

{ return s1.Compare(s2) != 0; }

bool operator!=(LPCTSTR s1, const CString& s2)

{ return s2.Compare(s1) != 0; }

bool operator<(const CString& s1, const CString& s2)

{ return s1.Compare(s2) < 0; }

bool operator<(const CString& s1, LPCTSTR s2)

{ return s1.Compare(s2) < 0; }

bool operator<(LPCTSTR s1, const CString& s2)

{ return s2.Compare(s1) > 0; }

bool operator>(const CString& s1, const CString& s2)

{ return s1.Compare(s2) > 0; }

bool operator>(const CString& s1, LPCTSTR s2)

{ return s1.Compare(s2) > 0; }

bool operator>(LPCTSTR s1, const CString& s2)

{ return s2.Compare(s1) < 0; }

bool operator<=(const CString& s1, const CString& s2)

{ return s1.Compare(s2) <= 0; }

bool operator<=(const CString& s1, LPCTSTR s2)

{ return s1.Compare(s2) <= 0; }

bool operator<=(LPCTSTR s1, const CString& s2)

{ return s2.Compare(s1) >= 0; }

bool operator>=(const CString& s1, const CString& s2)

{ return s1.Compare(s2) >= 0; }

bool operator>=(const CString& s1, LPCTSTR s2)

{ return s1.Compare(s2) >= 0; }

bool operator>=(LPCTSTR s1, const CString& s2)

{ return s2.Compare(s1) <= 0; }

////////////////////////////////////////////////////////////////////////////////

void ConstructElements(CString* pElements, int nCount)

{

 assert(nCount == 0 

  AfxIsValidAddress(pElements, nCount * sizeof(CString)));

for (; nCount--; ++pElements)

  memcpy(pElements, &AfxGetEmptyString(), sizeof(*pElements));

}

void DestructElements(CString* pElements, int nCount)

{

 assert(nCount == 0 

  AfxIsValidAddress(pElements, nCount * sizeof(CString)));

for (; nCount--; ++pElements)

  pElements->~CString();

}

void CopyElements(CString* pDest, const CString* pSrc, int nCount)

{

 assert(nCount == 0 

  AfxIsValidAddress(pDest, nCount * sizeof(CString)));

 assert(nCount == 0 

  AfxIsValidAddress(pSrc, nCount * sizeof(CString)));

for (; nCount--; ++pDest, ++pSrc)

  *pDest = *pSrc;

}

MFC 字符串类CString 源代码的更多相关文章

  1. VS2010/MFC编程入门之四十三(MFC常用类:CTime类和CTimeSpan类)

    上一节中鸡啄米讲了MFC常用类CString类的用法,本节继续讲另外两个MFC常用类-日期和时间类CTime类和CTimeSpan类. 日期和时间类简介 CTime类的对象表示的时间是基于格林威治标准 ...

  2. VS2010-MFC(MFC常用类:CTime类和CTimeSpan类)

    转自:http://www.jizhuomi.com/software/230.html 上一节讲了MFC常用类CString类的用法,本节继续讲另外两个MFC常用类-日期和时间类CTime类和CTi ...

  3. MFC中的CString类使用方法指南

    MFC中的CString类使用方法指南 原文出处:codeproject:CString Management [禾路:这是一篇比较老的资料了,但是对于MFC的程序设计很有帮助.我们在MFC中使用字符 ...

  4. VS2010/MFC编程入门之四十二(MFC常用类:CString类)

    上一节鸡啄米讲了分割窗口的有关知识,本节开始讲解MFC的一些常用类,先来说说CString类. CString类简介 CString类作为MFC的常用类,当之无愧.可以这样说,只要是从事MFC开发,基 ...

  5. VS2010-MFC(MFC常用类:CString类)

    转自:http://www.jizhuomi.com/software/228.html CString类简介 CString类作为MFC的常用类,当之无愧.可以这样说,只要是从事MFC开发,基本都会 ...

  6. MFC常用类

    CString CStringT 操作可变长度字符串的模板类CStringT有三个实例:CString.CStringA和CStringW,它们分别提供对TCHAR.char和wchar_t字符类型的 ...

  7. ATL、MFC、WTL CString 的今生前世(转载)

    转载:https://www.cnblogs.com/tekkaman/archive/2011/04/20/2022650.html 上文分析了ATL.MFC CString的设计和实现,我们不禁会 ...

  8. C++字符串类

    好久没有写过程序,最近想学习下界面库的开发,基于directui的界面个人觉得还不错,像金山的源代码和duilib都是不错的.本人想结合二者做一个轻量级的界面库,同时又不依赖于常用的MFC.WTL等. ...

  9. C++自定义String字符串类,支持子串搜索

    C++自定义String字符串类 实现了各种基本操作,包括重载+号实现String的拼接 findSubStr函数,也就是寻找目标串在String中的位置,用到了KMP字符串搜索算法. #includ ...

随机推荐

  1. Eclipse配置tomcat后,启动tomcat,访问tomcat报404错误

    当你在Eclipse中新建一个工程,配置好tomcat,然后测试tomcat是否配置成功的时候,报404错误异常. 解决方法: 1,把工程文件删除,重新建立一个新的工程, 2,新建一个工程. 3,Ne ...

  2. ant常用命令

    1.ant -version

  3. python 调用nmap

    1.系统中需要安装nmap 2.系统中安装pip 2.安装python调用nmap的lib包 命令为:pip install python-nmap 以下是在centos系统下安装成功后的截图 在命令 ...

  4. android user build serial console

    在 init.rc 里有一段 on property:ro.debuggable=1 start console 当user debug时 ro.debuggable=0,console 不会被启动 ...

  5. 【转载】关于.NET里的内存泄漏

    所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中..Net 中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉.虽然.N ...

  6. CSS3之绽放的花朵(网页效果--每日一更)

    今天,带来的是纯CSS3打造的效果--绽放的花朵. 先来看效果吧:亲,请点击这里 这是纯CSS3样式打造的效果,关键是采用了animation属性和transform属性.详细请看下面代码. HTML ...

  7. 细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一

    细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一(转) ADO.NET Entity Framework        ADO.NET Entity Framework 是微软以 ADO.N ...

  8. 换个角度理解云计算之MapReduce

    上一篇简单讲了一下HDFS,简单来说就是一个叫做“NameNode”的大哥,带着一群叫做“DataNode”的小弟,完成了一坨坨数据的存储,其中大哥负责保存数据的目录,小弟们负责数据的真正存储,而大哥 ...

  9. PS 多次剪裁同一图片

    一个图品里面有两个小图,要分别抠出来. 我以前的做法是,先扣一个,重新打开文件,再扣另外一个. 今天发现一个简单的办法,不用重新打开文件. 就是在扣完第一个的时候,打开历史记录面板,双击 打开 动作, ...

  10. Lucene系列-分析器

    分析器介绍 搜索的基础是对文本信息进行分析,Lucene的分析工具在org.apache.lucene.analysis包中.分析器负责对文本进行分词.语言处理得到词条,建索引和搜索的时候都需要用到分 ...