背景:
基于某些不着边际想法,只为取得HTML页面上的所有“URL”和“文本”,其它的内容都不在关心之列。
问题:
对于“文本”搜索,如果搜索了除英文以外的语言还好说些,如果要搜索的内容是英文本,
那么就难以区分是“标记”还是“本文”了。对于“URL”的搜索,因为“标记”就是英文,
这样就绕回到“对于‘文本’搜索”。另外字母的大小写,被转义的字符,引号,尖括号,都得处理。
例如:
<a href="http://www.csdn.net" >csdn</a>
<script src="http://csdnimg.cn/xxxxxxxx.js" type="text/javascript"></script>
想要搜索“csdn”这个字符串,直接以字符串遍历的法能搜索到3个,其实呢只希望搜索到1个。
例如:
<a href="http://bbs.csdn.net" >论坛</a>
<a href="http://bbs.csdn.net" >论 坛</a>
<a href="http://bbs.csdn.net" >论 坛</a>
想要搜索“论坛”这个字符串,按语义上讲,希望在搜索时能搜到3个。
但直接以字符串遍历的法能搜到1个,原因在于加了“空格”后的字符串,
计算机不知道对于人来讲意思并没有变。
总结:
1:直接搜索特定字符串,不多了就是少了。
2:尝试过MS的COM库,功能强大且齐全,但耗费的资源也相当多。
3:耳熟能详的搜索引擎也跑过几个回合,因没有耐心翻遍所有网页只好放弃。
结论:
只能把HTML页面完整的解析完毕才能达找到想到的东西,尽管不是全部,但情况要好很多。
方法:
HTML语句结构是:<a href="http://www.csdn.net" >aaaa</a> 或 <link href="/favicon.ico" />
等等一连串类似的语句组成,并且只有嵌套没有循环(脚本只能算上面提到的“文本”)。
分界符(这个词本人自己的称呼)使用的是“ <>""''=空格 ”,把两个分界符之间的内容看作一个链表节点,
“标记”a与“标记”/a是“父”节点与“子”节点的关系,“标记”a与“标记”href是“兄弟”节点的关系。
这样的好处是不用关心“标记”含义,就可以把整个页面解析成一个二维链表。
纵向可以遍历“标记”和“文本”,横向可以找到“文本”对应用“URL”。
当然实际情况要复杂的多,种种异常情况都要考虑。如:转意字符,脚本中的括号对称验证等等,
最糟糕是碰到错误的语法,或者根本就不是HTML页面(这个就不属性本文说明范围了)。
//////////////////////////////以上内容于 2011-12-17 18:01 添加/////////////////////////////////////////
1:较“HTML解析-第一版(C/C++)” 减少了内存拷贝,速度相对提高很多。
2:代码在VS2008下测试通过。#define _UNICODE #define _WIN32_WINNT 0x0600
3:解析方法:类似于构建一个map表(STL模板库里的map不利于阅读,可以参考MFC类库的CMap),最终组成一个二维的单向链表。
4:CHtmlObject 类负责解析HTML“标记”和“属性”。
//////////////////////////////////////////////////////////////////////////////////////////CHtmlObject.h//////////////////////////////////////////////////////////////////////////
#pragma once
/*****************************************************************************************************************
created: 2011/12/03
author: hmm7e (hmm7e_z@126.com)
*****************************************************************************************************************/
class CHtmlObject
{
public:
//
static BOOL IsSpace(TCHAR tcLetter);
protected:
struct tagNode
{
LPCTSTR s_pszKey;
LPCTSTR s_pszValue;
struct tagNode * s_pstRight; //attribute of tag
struct tagNode * s_pstNext; //next tag
};
public:
CHtmlObject(void);
virtual ~CHtmlObject(void);
//
enum {CHARSET_UTF8,CHARSET_UNICODE,CHARSET_MULTIBYTE}TextCharset;
protected:
//
tagNode * InnerAllocNode();
void InnerFreeNode(tagNode * lpstNode);
void InnerLinkNextNode(tagNode * lpstNode);
void InnerLinkRightNode(tagNode * lpstTagNode,tagNode * lpstNode);
void InnerCleanupNode();
void InnerCleanupRightNode(tagNode * lpstNode);
public:
//
void AutoTakeSnapshot(PBYTE lpszString,UINT nStringLen);
void TakeSnapshot(PBYTE lpszString,UINT nStringLen,UINT nFromCharset );
void DeleteSnapshot();
//
void Parse();
private:
//
void InnerParse();
LPTSTR InnerSplitComment(tagNode * lpstNode,LPTSTR lpszTagString);
LPTSTR InnerSplitTag(tagNode * lpstNode,LPTSTR lpszTagString);
LPTSTR InnerSplitContent(tagNode * lpstNode,LPTSTR lpszTagString);
LPTSTR InnerSplitText(tagNode * lpstNode,LPTSTR lpszTagString);
LPTSTR InnerSplitScript(tagNode * lpstNode,LPTSTR lpszTagString);
LPTSTR InnerSplitStyle(tagNode * lpstNode,LPTSTR lpszTagString);
protected:
//
LPTSTR m_pszSnapshotBuffer;
UINT m_nSnapshotBufferLen;
UINT m_nSnapshotStringLen;
//
tagNode * m_pstHead;
tagNode * m_pstTail;
};
//////////////////////////////////////////////////////////////////////////////////////////CHtmlObject.h//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////CHtmlObject.cpp//////////////////////////////////////////////////////////////////////////#pragma once/*****************************************************************************************************************created: 2011/12/03author: hmm7e (hmm7e_z@126.com)*****************************************************************************************************************/#include "HtmlObject.h"//BOOL CHtmlObject::IsSpace(TCHAR tcLetter){ //以下字符在HTML标记里都算是空格。 return (tcLetter == _T(' ') || tcLetter == _T('\r') ||tcLetter == _T('\n') ||tcLetter == _T('\t') );}CHtmlObject::CHtmlObject(void){ m_pszSnapshotBuffer = NULL; m_nSnapshotBufferLen = 0; m_nSnapshotStringLen = 0; m_pstHead = NULL; m_pstTail = NULL;}CHtmlObject::~CHtmlObject(void){ DeleteSnapshot();}//CHtmlObject::tagNode * CHtmlObject::InnerAllocNode(){ CHtmlObject::tagNode * pstResult = new CHtmlObject::tagNode; if( pstResult ) { ::ZeroMemory((LPVOID)pstResult,sizeof(CHtmlObject::tagNode)); } return pstResult;}void CHtmlObject::InnerFreeNode(CHtmlObject::tagNode * lpstNode){ if( lpstNode ) delete lpstNode;}void CHtmlObject::InnerLinkNextNode(tagNode * lpstNode){ //链接到“尾”结点。 //1:如果没有“头”节点,那么表示链表是“空”的。 //2:如果已经存“头”节点,那么就链接新节点到“尾”节点,并重新记录“尾”节点指针。 if( m_pstHead == NULL ) { m_pstHead = lpstNode; m_pstTail = lpstNode; } else { m_pstTail->s_pstNext = lpstNode; m_pstTail = lpstNode; }#ifdef _DEBUG if( lpstNode->s_pszKey ) { ::OutputDebugString(_T("--")); ::OutputDebugString(lpstNode->s_pszKey); ::OutputDebugString(_T("--\r\n")); } if( lpstNode->s_pszValue ) { ::OutputDebugString(_T("--")); ::OutputDebugString(lpstNode->s_pszValue); ::OutputDebugString(_T("--\r\n")); }#endif //_DEBUG}void CHtmlObject::InnerLinkRightNode(tagNode * lpstTagNode,tagNode * lpstNode){ //链接到“属性”的“头”节点。 //1:把现有的“属性”链表,链接到当前新节点的下。 //2:把当前节点做为“头”节点保存。 lpstNode->s_pstRight = lpstTagNode->s_pstRight; lpstTagNode->s_pstRight = lpstNode;#ifdef _DEBUG if( lpstNode->s_pszKey ) { ::OutputDebugString(_T("-->")); ::OutputDebugString(lpstNode->s_pszKey); ::OutputDebugString(_T("<--\r\n")); } if( lpstNode->s_pszValue ) { ::OutputDebugString(_T("-->")); ::OutputDebugString(lpstNode->s_pszValue); ::OutputDebugString(_T("<--\r\n")); }#endif //_DEBUG}void CHtmlObject::InnerCleanupNode(){ //循环清除所有节点。如果存在“属性”节点一并清除。 CHtmlObject::tagNode * pstPrev = NULL; while( m_pstHead ) { pstPrev = m_pstHead; m_pstHead = m_pstHead->s_pstNext; //first InnerCleanupRightNode(pstPrev); //second InnerFreeNode(pstPrev); } m_pstHead = NULL; m_pstTail = NULL;}void CHtmlObject::InnerCleanupRightNode(CHtmlObject::tagNode * lpstNode){ //循环清除所有“属性”节点。 CHtmlObject::tagNode * pstHead = lpstNode->s_pstRight; CHtmlObject::tagNode * pstPrev = NULL; while( pstHead ) { pstPrev = pstHead; pstHead = pstHead->s_pstRight; InnerFreeNode(pstPrev); } pstHead = NULL; pstPrev = NULL;}//void CHtmlObject::AutoTakeSnapshot(PBYTE lpszString,UINT nStringLen){ if( lpszString && nStringLen > 0) { //根据数据头自动判断是否需要转换数据到当前应程所使用的编码。 if( nStringLen >= 2 ) { if( lpszString[0] == 0xFF && lpszString[1] == 0xFE ) // skip 0xFF,0xFE { TakeSnapshot(lpszString+2,nStringLen-2,CHtmlObject::CHARSET_UNICODE); } else if( lpszString[0] == 0xEF && lpszString[1] == 0xBB && lpszString[2] == 0xBF )// skip 0xEF,0xBB,0xBF { TakeSnapshot(lpszString+3,nStringLen-3,CHtmlObject::CHARSET_UTF8); } else { TakeSnapshot(lpszString,nStringLen,CHtmlObject::CHARSET_MULTIBYTE); } } else { TakeSnapshot(lpszString,nStringLen,CHtmlObject::CHARSET_MULTIBYTE); } }}void CHtmlObject::TakeSnapshot(PBYTE lpszString,UINT nStringLen,UINT nFromCharset ){ //delete old snapshot DeleteSnapshot(); if( lpszString && nStringLen > 0 ) { //transform to TCHAR if( CHtmlHelper::CHARSET_UTF8 == nFromCharset ) {#ifdef _UNICODE m_nSnapshotBufferLen = nStringLen; m_pszSnapshotBuffer = new TCHAR[m_nSnapshotBufferLen]; ::memset((LPVOID)m_pszSnapshotBuffer,0,m_nSnapshotBufferLen*sizeof(TCHAR)); m_nSnapshotStringLen = ::MultiByteToWideChar(CP_UTF8,0,(LPCSTR)lpszString,nStringLen,m_pszSnapshotBuffer,m_nSnapshotBufferLen);#else ::OutputDebugString(_T("no support"));#endif //_UNICODE } else if( CHtmlHelper::CHARSET_UNICODE == nFromCharset ) {#ifdef _UNICODE m_nSnapshotBufferLen = nStringLen; m_pszSnapshotBuffer = new TCHAR[m_nSnapshotBufferLen]; ::memset((LPVOID)m_pszSnapshotBuffer,0,m_nSnapshotBufferLen*sizeof(TCHAR)); ::memcpy((LPVOID)m_pszSnapshotBuffer,lpszString,nStringLen);#else m_nSnapshotBufferLen = nStringLen/2+1; m_pszSnapshotBuffer = new TCHAR[m_nSnapshotBufferLen]; ::memset((LPVOID)m_pszSnapshotBuffer,0,m_nSnapshotBufferLen*sizeof(TCHAR)); m_nSnapshotStringLen = ::WideCharToMultiByte(CP_ACP,0,(LPWSTR)lpszString,nStringLen,(LPSTR)m_pszSnapshotBuffer,m_nSnapshotBufferLen,NULL,NULL);#endif //_UNICODE } else {#ifdef _UNICODE m_nSnapshotBufferLen = nStringLen; m_pszSnapshotBuffer = new TCHAR[m_nSnapshotBufferLen]; ::memset(m_pszSnapshotBuffer,0,m_nSnapshotBufferLen*sizeof(TCHAR)); m_nSnapshotStringLen = ::MultiByteToWideChar(CP_ACP,0,(LPCSTR)lpszString,nStringLen,m_pszSnapshotBuffer,m_nSnapshotBufferLen);#else m_nSnapshotBufferLen = nStringLen; m_pszSnapshotBuffer = new TCHAR[m_nSnapshotBufferLen]; ::memset((LPVOID)m_pszSnapshotBuffer,0,m_nSnapshotBufferLen*sizeof(TCHAR)); ::memcpy((LPVOID)m_pszSnapshotBuffer,lpszString,nStringLen);#endif //_UNICODE } }}void CHtmlObject::DeleteSnapshot(){ //先清除树型表。 InnerCleanupNode(); if( m_pszSnapshotBuffer ) delete []m_pszSnapshotBuffer; m_pszSnapshotBuffer = NULL; m_nSnapshotBufferLen = 0; m_nSnapshotStringLen = 0;}//void CHtmlObject::Parse(){#ifdef _AFX CString strTrace; strTrace.Format(_T("CHtmlObject::Parse() --begin-->(%d)\r\n"),::GetTickCount()); ::OutputDebugString(strTrace);#endif //_AFX InnerParse();#ifdef _AFX strTrace.Format(_T("CHtmlObject::Parse() --end-->(%d)\r\n"),::GetTickCount()); ::OutputDebugString(strTrace);#endif //_AFX}//void CHtmlObject::InnerParse(){ LPTSTR pszFind = m_pszSnapshotBuffer; //跳过所有“空格” while( *pszFind != _T('\0') && CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } //直到碰到'\0'就退出 do { // 不是“\0”,并且第一个字符为“<”则置换为“\0”,否则什么也不做。 //这么写的原因就在于InnerSplitContent()返回后 “<”可能已经被置换成“\0”。 if( *pszFind != _T('\0') && *pszFind == _T('<') ) { //把“<”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //下一个字符。 pszFind++; } // 不是“\0” if( *pszFind != _T('\0') ) { //是否为注释 if( *pszFind == _T('!') ) { //申请一个点节。 tagNode *pstNode = InnerAllocNode(); //解析注释,返回的是注释后面的内容。 pszFind = InnerSplitComment(pstNode,pszFind); //链接到“链表”。(下) InnerLinkNextNode(pstNode); } else { //申请一个点节。 tagNode *pstNode = InnerAllocNode(); //解析tag,返回的是tag后面的内容。 pszFind = InnerSplitTag(pstNode,pszFind); //解析content返回的是content后面的内容。 pszFind = InnerSplitContent(pstNode,pszFind); //链接到“链表”。(下) InnerLinkNextNode(pstNode); } } }while( *pszFind!= _T('\0') );}LPTSTR CHtmlObject::InnerSplitComment(CHtmlObject::tagNode * lpstNode,LPTSTR lpszTagString){ LPTSTR pszFind = lpszTagString; //指向注释开头(已经跳过“<”字符) lpstNode->s_pszKey = pszFind; //如果为 <!-- *** --> if( ::_tcsnicmp(pszFind+1,_T("--"),2) == 0 ) { //跳过注释标记“头”,开始查找。 pszFind += 3; //查找到注释结尾,并给结尾加“\0”。 while( ::_tcsnicmp(pszFind,_T("-->"),3) != 0 ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { //把“>”置换为“\0”,做为注释结尾 *(pszFind+2) = _T('\0'); //指向新的节点或内容。 pszFind += 3; } } //否则为 <! *** > else { //查找到注释结尾,并给结尾加“\0”。 while( *pszFind != _T('\0') && *pszFind != _T('>') ) { //下一个字符 pszFind++; } //不能是“\0” if( *pszFind != _T('\0') ) { //把“>”置换为“\0”,做为注释结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; } } //找到一个“<” while( *pszFind != _T('\0') && *pszFind != _T('<') ) { //下一个字符 pszFind++; } return pszFind;}LPTSTR CHtmlObject::InnerSplitTag(CHtmlObject::tagNode * lpstNode,LPTSTR lpszTagString){ LPTSTR pszFind = lpszTagString; //指向开头(已经跳过“<”字符) lpstNode->s_pszKey = pszFind; //查找tag结尾,并给结尾加“\0”。 while( *pszFind != _T('\0') && *pszFind != _T('>') && !CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { if( *pszFind == _T('>') ) { //把“>”置换为“\0”,做为注释结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; //此tag没有属性,什么也不做了。 } else { //把“space,\r,\n,\t ”置换为“\0”,做为注释结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; //如果不是结束标记,表示此tag有“属性”还需要解析“属性”。 if( *lpstNode->s_pszKey != _T('/') ) { //跳过所有“空格”,找到第一个属性。 while( *pszFind != _T('\0') && CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } //循环分析“属性”。 while( *pszFind != _T('\0') && *pszFind != _T('<') && *pszFind != _T('>') ) { //例: // key="value" key=value //跳过空格 while( *pszFind != _T('\0') && CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { //申请一个点节。 tagNode *pstAttributeNode = InnerAllocNode(); //指向“属性”Key。 pstAttributeNode->s_pszKey = pszFind; //查找key的末尾. while( *pszFind != _T('\0') && *pszFind != _T('=') && *pszFind != _T('>') ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { if( *pszFind == _T('>') ) { //把“>”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; //链接到“链表”(右)。 InnerLinkRightNode(lpstNode,pstAttributeNode); //已经碰到“>”,需要跳出。 break; } else { //把“=”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; //不是“\0” if( *pszFind != _T('\0') ) { if( *pszFind == _T('"') ) { //跳过“"” pszFind++; //指向“属性”key的Value。 pstAttributeNode->s_pszValue = pszFind; //查找Value的末尾. while( *pszFind != _T('\0') && *pszFind != _T('\"') && *pszFind != _T('>') ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { //把“",> ”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; } } else if( *pszFind == _T('\'') ) { //跳过“'” pszFind++; //指向“属性”key的Value。 pstAttributeNode->s_pszValue = pszFind; //查找Value的末尾. while( *pszFind != _T('\0') && *pszFind != _T('\'') && *pszFind != _T('>') ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { //把“",<space> ”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; } } else { //指向“属性”key的Value。 pstAttributeNode->s_pszValue = pszFind; //查找Value的末尾. while( *pszFind != _T('\0') && *pszFind != _T(' ') && *pszFind != _T('>') ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { //把“ ”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; } } } } } //链接到“链表”(右)。 InnerLinkRightNode(lpstNode,pstAttributeNode); } } //跳过这个无用的字符。 if( *pszFind == _T('>') ) { //指向新的节点或内容。 pszFind++; } } } } return pszFind;}LPTSTR CHtmlObject::InnerSplitContent(CHtmlObject::tagNode * lpstNode,LPTSTR lpszTagString){ LPTSTR pszFind = lpszTagString; if( ::_tcsnicmp(lpstNode->s_pszKey,_T("script"),6) == 0 ) { pszFind = InnerSplitScript(lpstNode,pszFind); } else if( ::_tcsnicmp(lpstNode->s_pszKey,_T("style"),5) == 0 ) { pszFind = InnerSplitStyle(lpstNode,pszFind); } else { pszFind = InnerSplitText(lpstNode,pszFind); } return pszFind;}LPTSTR CHtmlObject::InnerSplitText(CHtmlObject::tagNode * lpstNode,LPTSTR lpszTagString){ LPTSTR pszFind = lpszTagString; //跳过所有“空格” while( *pszFind != _T('\0') && CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } //如果 _T('<') 表示没有文本。 if( *pszFind != _T('<') ) { //指向可见文本。 lpstNode->s_pszValue = pszFind; //查找文本结尾。 while( *pszFind != _T('\0') && *pszFind != _T('<') && !CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } //不是“\0” if( *pszFind != _T('\0') ) { if( *pszFind == _T('<') ) { //把“<”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; } else { //把“space,\r,\n,\t,”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; //找到一个“<” while( *pszFind != _T('\0') && *pszFind != _T('<') ) { //下一个字符 pszFind++; } } } } return pszFind;}LPTSTR CHtmlObject::InnerSplitScript(tagNode * lpstNode,LPTSTR lpszTagString){ LPTSTR pszFind = lpszTagString;#define SCRIPT_MARK_MAX 1024 UINT nMarkIndex = 0; TCHAR szMark[SCRIPT_MARK_MAX] = {_T('\0')}; //max 1024 //跳过所有“空格” while( *pszFind != _T('\0') && CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } if( *pszFind != _T('\0') && *pszFind != _T('<') ) { //指向可见文本。 lpstNode->s_pszValue = pszFind; while( *pszFind != _T('\0') ) { //如果字符被“',"”包围则为字符串,这期间不计算注释。 if( szMark[nMarkIndex] != _T('\'') && szMark[nMarkIndex] != _T('\"') ) { //如果是// abc 则跳过。 if( ::_tcsnicmp(pszFind,_T("//"),2) == 0 ) { //跳过注释“头”。 pszFind +=2; //查找注释“尾”。 while( *pszFind != _T('\0') && *pszFind != _T('\n') ) { pszFind++; } //跳过注释“尾”。 if( *pszFind != _T('\0') ) pszFind++; } //如果是/* abc */则跳过。 else if( ::_tcsnicmp(pszFind,_T("/*"),2) == 0 ) { //跳过注释“头”。 pszFind +=2; //查找注释“尾”。 while( ::_tcsnicmp(pszFind,_T("*/"),2) != 0 ) { pszFind++; } //跳过注释“尾”。 if( *pszFind != _T('\0') ) pszFind +=2; } } if( *pszFind == _T('\\') && ( *(pszFind+1) == _T('\\') || *(pszFind+1) == _T('(') || *(pszFind+1) == _T(')') || *(pszFind+1) == _T('[') || *(pszFind+1) == _T(']') || *(pszFind+1) == _T('{') || *(pszFind+1) == _T('}') || *(pszFind+1) == _T('\'') || *(pszFind+1) == _T('\"') ) ) { //转意字符 pszFind+=2; } else if( *pszFind == _T('{') || *pszFind == _T('(') || *pszFind == _T('[') || (*pszFind == _T('\'') || *pszFind == _T('\"')) ) { if( szMark[nMarkIndex] != _T('\'') && szMark[nMarkIndex] != _T('\"') ) { if( nMarkIndex < SCRIPT_MARK_MAX ) { if( nMarkIndex == 0 && szMark[nMarkIndex] == _T('\0') ) szMark[nMarkIndex] = *pszFind; else szMark[++nMarkIndex] = *pszFind; } } else if( szMark[nMarkIndex] == *pszFind ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T('}') ) { if( szMark[nMarkIndex] == _T('{') ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T(')') ) { if( szMark[nMarkIndex] == _T('(') ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T(']') ) { if( szMark[nMarkIndex] == _T('[') ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T('<') && szMark[0] == _T('\0') ) //nMarkIndex == 0 && { //把“<”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; break; } else { pszFind++; } } } return pszFind;}LPTSTR CHtmlObject::InnerSplitStyle(CHtmlObject::tagNode * lpstNode,LPTSTR lpszTagString){ LPTSTR pszFind = lpszTagString;#define STYLE_MARK_MAX 1024 UINT nMarkIndex = 0; TCHAR szMark[STYLE_MARK_MAX] = {_T('\0')}; //max 1024 //跳过所有“空格” while( *pszFind != _T('\0') && CHtmlObject::IsSpace(*pszFind) ) { //下一个字符 pszFind++; } if( *pszFind != _T('\0') && *pszFind != _T('<') ) { //指向可见文本。 lpstNode->s_pszValue = pszFind; while( *pszFind != _T('\0') ) { //如果字符被“(,',"”包围则为字符串,这期间不计算注释。 if( szMark[nMarkIndex] != _T('(') && szMark[nMarkIndex] != _T('\'') && szMark[nMarkIndex] != _T('\"') ) { //如果是/* abc */则跳过。 if( ::_tcsnicmp(pszFind,_T("/*"),2) == 0 ) { //跳过注释“头”,查找注释“尾”。 pszFind +=2; while( ::_tcsnicmp(pszFind,_T("*/"),2) != 0 ) { pszFind++; } //跳过注释“尾”。 if( *pszFind != _T('\0') ) pszFind +=2; } } if( *pszFind == _T('{') || *pszFind == _T('(') || *pszFind == _T('[') || (*pszFind == _T('\'') || *pszFind == _T('\"')) ) { if( szMark[nMarkIndex] != _T('\'') && szMark[nMarkIndex] != _T('\"') ) { if( nMarkIndex < STYLE_MARK_MAX ) { if( nMarkIndex == 0 && szMark[nMarkIndex] == _T('\0') ) szMark[nMarkIndex] = *pszFind; else szMark[++nMarkIndex] = *pszFind; } } else if( szMark[nMarkIndex] == *pszFind ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T('}') ) { if( szMark[nMarkIndex] == _T('{') ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T(')') ) { if( szMark[nMarkIndex] == _T('(') ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T(']') ) { if( szMark[nMarkIndex] == _T('[') ) { if( nMarkIndex >0 ) szMark[nMarkIndex--] = _T('\0'); else szMark[nMarkIndex] = _T('\0'); } pszFind++; } else if( *pszFind == _T('<') && szMark[0] == _T('\0') ) //nMarkIndex == 0 && { //把“<”置换为“\0”,做为结尾。 *pszFind = _T('\0'); //指向新的节点或内容。 pszFind++; break; } else { pszFind++; } } } return pszFind;}//////////////////////////////////////////////////////////////////////////////////////////CHtmlObject.cpp//////////////////////////////////////////////////////////////////////////5:CHtmlHelper做为派生类,负责读取解析后的“标记”和“属性”。这里只写了两个方法,实际应用请自行添加。
//////////////////////////////////////////////////////////////////////////////////////////CHtmlHelper.h//////////////////////////////////////////////////////////////////////////
#pragma once
/*****************************************************************************************************************
created: 2011/12/03
author: hmm7e (hmm7e_z@126.com)
*****************************************************************************************************************/
#include "HtmlObject.h"
class CHtmlHelper:public CHtmlObject
{
public:
CHtmlHelper(void);
virtual ~CHtmlHelper(void);
public:
//
LPCTSTR GetFirstLink();
LPCTSTR GetNextLink();
LPCTSTR GetFirstContent();
LPCTSTR GetNextContent();
LPCTSTR SearchText(LPCTSTR lpszText);
protected:
//
CHtmlObject::tagNode * m_pstCur;
};
//////////////////////////////////////////////////////////////////////////////////////////CHtmlHelper.h//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////CHtmlHelper.cpp//////////////////////////////////////////////////////////////////////////#pragma once/*****************************************************************************************************************created: 2011/12/03author: hmm7e (hmm7e_z@126.com)*****************************************************************************************************************/#include "HtmlHelper.h"#pragma warning(disable: 4996) CHtmlHelper::CHtmlHelper(){}CHtmlHelper::~CHtmlHelper(){}//LPCTSTR CHtmlHelper::GetFirstLink(){ LPCTSTR pszResult = NULL; m_pstCur = m_pstHead; while( m_pstCur && !pszResult ) { if( 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("script"),6) && 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("style"),5) ) { CHtmlObject::tagNode * pstAttributeCur = m_pstCur->s_pstRight; while( pstAttributeCur ) { if( 0 == ::_tcsnicmp(pstAttributeCur->s_pszKey,_T("href"),4) || 0 == ::_tcsnicmp(pstAttributeCur->s_pszKey,_T("src"),3) ) { //return pszResult = pstAttributeCur->s_pszValue; break ; } else { pstAttributeCur = pstAttributeCur->s_pstRight; } } } m_pstCur = m_pstCur->s_pstNext; } return pszResult;}LPCTSTR CHtmlHelper::GetNextLink(){ LPCTSTR pszResult = NULL; while( m_pstCur && !pszResult ) { if( 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("script"),6) && 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("style"),5) ) { CHtmlObject::tagNode * pstAttributeCur = m_pstCur->s_pstRight; while( pstAttributeCur ) { if( 0 == ::_tcsnicmp(pstAttributeCur->s_pszKey,_T("href"),4) || 0 == ::_tcsnicmp(pstAttributeCur->s_pszKey,_T("src"),3) ) { //return pszResult = pstAttributeCur->s_pszValue; break ; } else { pstAttributeCur = pstAttributeCur->s_pstRight; } } } m_pstCur = m_pstCur->s_pstNext; } return pszResult;}LPCTSTR CHtmlHelper::GetFirstContent(){ LPCTSTR pszResult = NULL; m_pstCur = m_pstHead; while( m_pstCur && !pszResult ) { if( 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("script"),6) && 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("style"),5) ) { if( m_pstCur->s_pszValue ) pszResult = m_pstCur->s_pszValue; } m_pstCur = m_pstCur->s_pstNext; } return pszResult;}LPCTSTR CHtmlHelper::GetNextContent(){ LPCTSTR pszResult = NULL; while( m_pstCur && !pszResult ) { if( 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("script"),6) && 0 != ::_tcsnicmp(m_pstCur->s_pszKey,_T("style"),5) ) { if( m_pstCur->s_pszValue ) pszResult = m_pstCur->s_pszValue; } m_pstCur = m_pstCur->s_pstNext; } return pszResult;}//LPCTSTR CHtmlHelper::SearchText(LPCTSTR lpszText){ LPCTSTR pszResult = NULL; CHtmlObject::tagNode *pstCur = m_pstHead; while( pstCur && !pszResult) { if( 0 != ::_tcsnicmp(pstCur->s_pszKey,_T("script"),6) && 0 != ::_tcsnicmp(pstCur->s_pszKey,_T("style"),5) ) { if( pstCur->s_pszValue ) { if( (NULL != ::StrStrI(pstCur->s_pszValue,lpszText)) ) pszResult = pstCur->s_pszValue; } } pstCur = pstCur->s_pstNext; } return pszResult;}#pragma warning(default: 4996) //////////////////////////////////////////////////////////////////////////////////////////CHtmlHelper.cpp//////////////////////////////////////////////////////////////////////////