C/C++解析 HTML

本文在HMM7E的博文http://blog.csdn.net/hmm7e/article/details/7071705 HTML解析-第二版(C/C++)上修正了小部分错误,感谢他给予我的帮助

经改动后的工具类以及使用类大家可直接使用

基于某些不着边际想法,仅仅为取得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页面完整的解析完成才干达找到想到的东西,虽然不是所有,但情况要好非常多。

思路:

1.初步分析全部的HTML标签,将其分出必要的层次;

2.层次较高的标签能够对象化,而层次低一些的标签或元素依照用途及使用频率分别对待。

3.凡对象化的标签。在C语言中都能够声明为结构,未对象化的元素能够按性质以对应的数据类型进行存储。

要求:

1.不是全部的标签和元素都能够对象化的。那样会很复杂;

2.全部被对象化的标签都必须写一套专用的解释和处理程序;

3.上述思路适合数据库的存储。

方法:

HTML语句结构是:<a href="http://www.csdn.net" >aaaa</a> 或 <link href="/favicon.ico" />

等等一连串类似的语句组成,而且仅仅有嵌套没有循环(脚本仅仅能算上面提到的“文本”)。

分界符(这个词本人自己的称呼)使用的是“ <>""''=空格 ”,把两个分界符之间的内容看作一个链表节点,

“标记”a与“标记”/a是“父”节点与“子”节点的关系,“标记”a与“标记”href是“兄弟”节点的关系。

这种优点是不用关心“标记”含义,就能够把整个页面解析成一个二维链表。

纵向能够遍历“标记”和“文本”,横向能够找到“文本”相应用“URL”。

当然实际情况要复杂的多,种种异常情况都要考虑。

如:转意字符,脚本中的括号对称验证等等。

最糟糕是碰到错误的语法,或者根本就不是HTML页面(这个就不属性本文说明范围了)。

还是一样

1:较“HTML解析-第一版(C/C++)” 降低了内存拷贝,速度相对提高非常多。

2:代码在VS2008,VS2013下測试通过。

#define _UNICODE #define _WIN32_WINNT 0x0600

3:解析方法:类似于构建一个map表(STL模板库里的map不利于阅读,能够參考MFC类库的CMap),终于组成一个二维的单向链表。

4:CHtmlObject 类负责解析HTML“标记”和“属性”。

//////////////////////////////////////////////////////////////////////////////////////////CHtmlObject.h//////////////////////////////////////////////////////////////////////////

#ifndef __JESONYANG_HTMLOBJECT_H__
#define __JESONYANG_HTMLOBJECT_H__

/*****************************************************************************************************************
created: 2011/12/03
author: JesonYang
blog: http://blog.csdn.net/yc7369
*****************************************************************************************************************/
#include <windows.h>
#include <tchar.h>
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();                                                             //分配新的html节点
        void InnerFreeNode(tagNode * lpstNode);                                                             //删除html节点
        void InnerLinkNextNode(tagNode * lpstNode);                             //下一个html节点
        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;

};
#endif
//////////////////////////////////////////////////////////////////////////////////////////CHtmlObject.h//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////CHtmlObject.cpp//////////////////////////////////////////////////author: JesonYang////////////////////////

#pragma once

/*****************************************************************************************************************
created: 2011/12/03
author: JesonYang
blog: http://blog.csdn.net/yc7369
*****************************************************************************************************************/


#include "HtmlObject.h"
#include "HtmlHelper.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//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////CHtmlHelper.h//////////////////////////////////////////////////////////////////////////

#ifndef __JESONYANG_HTMLHELPER_H__
#define __JESONYANG_HTMLHELPER_H__

/*****************************************************************************************************************
created: 2011/12/03
author: JesonYang
blog: http://blog.csdn.net/yc7369
*****************************************************************************************************************/

#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;
};

#endif


//////////////////////////////////////////////////////////////////////////////////////////CHtmlHelper.h//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////CHtmlHelper.cpp//////////////////////////////////////////////////////////////////////////

#pragma once

/*****************************************************************************************************************
created: 2011/12/03
author: JesonYang
blog: http://blog.csdn.net/yc7369
*****************************************************************************************************************/


#include "HtmlHelper.h"
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#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//////////////////////////////////////////////////////////////////////////