本文在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//////////////////////////////////////////////////////////////////////////