Regex在網頁處理中的應用四則

來源:互聯網
上載者:User
網頁|正則   Regex(Regular Expression)為字串模式比對提供了一種高效、方便的方法。幾乎所有進階語言都提供了對Regex的支援,或者提供了現成的程式碼程式庫供調用。本文以ASP環境中常見的處理任務為例,介紹Regex的應用技巧。

   一、檢驗密碼和郵件地址的格式

  我們的第一個執行個體示範Regex的一項準系統:抽象地描述任意複雜的字串。它的意思就是,Regex給予程式員一種形式化的字串描述方法,只需很少的代碼即可描述出應用遇到的任一字元串模式。例如,對於不從事技術工作的人來說,密碼格式的要求可以描述如下:密碼的第一個字元必須是字母,密碼最少4個字元且不超過15個字元,密碼不能包含除字母、數字和底線以外的字元。

  作為程式員,我們必須把上面對密碼格式的自然語言描述轉換成其他形式,使得ASP頁面能夠理解並應用它來防止非法的密碼輸入。描述這個密碼格式的Regex是:^[a-zA-Z]\w{3,14}$。

  在ASP應用裡,我們可以把密碼驗證過程寫成可重用的函數,如下所示:

Function TestPassword(strPassword)
Dim re
Set re = new RegExp

re.IgnoreCase = false
re.global = false
re.Pattern = "^[a-zA-Z]\w{3,14}$"

TestPassword = re.Test(strPassword)
End Function

  下面我們把這個檢驗密碼格式的Regex和自然語言描述對比著看看:

  密碼的第一個字元必須是字母:Regex描述是“^[a-zA-Z]”,其中“^”表示字串的開始,連字號告訴RegExp匹配指定範圍的所有字元。

  密碼最少4個字元且不超過15個字元:Regex描述是“{3,14}”。

  密碼不能包含除字母、數字和底線以外的字元:Regex描述是“\w”。

  幾點說明:{3,14}表示前面的模式比對至少3個、但不超過14個的字元(加上第一個字元就成了4到15個字元)。注意花括弧內的文法要求極其嚴格,不允許在逗號的兩邊加入空格。如果加入了空格,它將對Regex的含義產生影響,導緻密碼格式檢驗時產生錯誤。另外,上面的Regex末尾也沒有加上“$”字元。$字元使得Regex匹配字串直至末尾,確保合法的密碼後面沒有加上任何其他字元。

  類似於密碼格式檢驗,檢查email地址的合法性也是一個很常見的問題,用Regex進行簡單的email地址檢驗可以實現如下:

<%
Dim re
Set re = new RegExp

re.pattern = "^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$"
Response.Write re.Test("aabb@yahoo.com")
%>

   二、提取HTML頁面的特定部分

  從HTML頁面提取內容所面臨的主要問題是,我們必須尋找一種方法精確地識別出自己想要的那一部分內容。例如,下面是一個顯示新聞標題的HTML代碼片斷:

<table border="0" width="11%" class="Somestory">
<tr>
<td width="100%">
<p align="center">其他內容...</td>
</tr>
</table>
<table border="0" width="11%" class="Headline">
<tr>
<td width="100%">
<p align="center">伊拉克戰爭!</td>
</tr>
</table>
<table border="0" width="11%" class="Someotherstory">
<tr>
<td width="100%">
<p align="center">其他內容...</td>
</tr>
</table>

  觀察上述代碼,很容易看出新聞標題由位於中間的表格顯示,它的class屬性設定為Headline。如果HTML頁面非常複雜,使用Microsoft IE從5.0開始提供的一項附加功能可以只查看被選中部分頁面的HTML代碼,請訪問http://www.microsoft.com/Windows/ie/WebAccess/default.ASP瞭解詳情。對於本例,我們假定這是唯一class屬性設定為Headline的表格。現在我們要建立Regex,通過Regex找到這個Headline表格並把這個表格包含到自己的頁面中。首先是編寫支援Regex的代碼:

<%
Dim re, strHTML
Set re = new RegExp ' 建立Regex對象

re.IgnoreCase = true
re.Global = false ' 第一次匹配之後結束尋找
%>

  下面考慮一下我們要提取的地區:在這裡,我們要提取的是整個<table>結構,包括結束標記和新聞標題的文本。因此尋找的起始字元應該是<table>開始標記: re.Pattern = "<table.*(?=Headline)"。這個Regex匹配表格的開始標記,能夠返回開始標記直至“Headline”之間的所有內容(換行除外)。下面是返回已匹配HTML代碼的方法:

' 把所有匹配的HTML代碼放入Matches集合
Set Matches = re.Execute(strHTML)

' 顯示所有匹配的HTML代碼
For Each Item in Matches
Response.Write Item.Value
Next

' 顯示其中一項
Response.write Matches.Item(0).Value

  運行這段代碼處理前面顯示的HTML片斷,Regex返回一次匹配的內容如下: <table border="0" width="11%" class="。Regex中的“(?=Headline)”沒有擷取字元,所以不能看到表格class屬性的值。要擷取表格剩餘部分的代碼也相當簡單: re.Pattern = "<table.*(?=Headline)(.|\n)*?</table>"。其中:“(.|\n)”後面的“*”匹配0個到多個任一字元;而“?”使得“*”匹配範圍最小化,即在找到運算式的下一部分之前匹配儘可能少的字元。</table>是表格的結束標記。

  “?”限制符非常重要,它防止了運算式返回其他表格的代碼。例如對於前面給出的HTML代碼片斷,如果刪除這個“?”則返回內容將是:

<table border="0" width="11%" class="Headline">
<tr>
<td width="100%">
<p align="center">伊拉克戰爭!</td>
</tr>
</table>
<table border="0" width="11%" class="Someotherstory">
<tr>
<td width="100%">
<p align="center">其他內容...</td>
</tr>
</table>


  返回的內容不僅包含了Headline表的<table>標記,而且還包含了Someotherstory表格,由此可以看出,這裡的“?”是必不可少的。

  本例假設了一些相當理想化的前提。實際應用中情況往往要複雜得多,特別是你對正在使用的源HTML代碼的編寫沒有任何影響力時,編寫ASP代碼尤為困難。最有效方法是,多花些時間分析待提取內容附近的HTML,經常地測試,確保提取出來的內容正是自己所需要的。另外,應當重視並處理Regex不能匹配源HTML頁面任何內容的情形。內容的更新可能非常快速,不要只因為別人改變了內容的格式而讓自己的頁面出現低級可笑的錯誤。

  三、解析文本資料檔案

  資料檔案的格式和種類很多,XML文檔、結構化文本甚至非結構化文本都經常成為ASP應用的資料來源。下面我們要看的一個例子是使用限定符的結構化文字檔。限定符(比如引號)表示字串各個部分不可分割,即使字串內部包含把記錄分隔成欄位的分隔字元也一樣。

  下面是一個簡單的結構化文字檔:

姓,名, 電話, 說明
孫,悟空, 312 555 5656, ASP很好
豬,八戒, 847 555 5656, 我是電影製片人

  這個檔案非常簡單,它的第一行是標題,下面兩行是用逗號作為分隔字元的記錄。要解析這個檔案也很簡單,只需先把檔案分割成行(根據分行符號號),然後把各個記錄按照欄位分割。但是,如果我們在某個欄位內容中加入了逗號:

姓,名, 電話, 說明
孫,悟空, 312 555 5656, 我喜歡ASP,還有VB和SQL
豬,八戒, 847 555 5656, 我是電影製片人

  解析第一個記錄時就會出現問題,因為在只認可逗號分隔字元的解析器看來它的最後一個欄位包含了兩個欄位的內容。為了避免出現這類問題,包含分隔字元的欄位必須用限定符包圍。單引號就是一種常用的限定符。把上面的文字檔加上單引號限定符之後,它的內容如下所示:

姓,名, 電話, 說明
孫,悟空, 312 555 5656, '我喜歡ASP,還有VB和SQL'
豬,八戒, 847 555 5656, '我是電影製片人'

  現在我們能夠肯定哪一個逗號是分隔字元、哪一個逗號是欄位內容了,即只需把引號內部出現的逗號視為欄位的內容。接下來我們要做的就是實現一個Regex解析器,由這個解析器確定何時根據逗號分割欄位、何時把逗號視為欄位內容。

  這裡的問題與大多數Regex所面臨的略有不同。通常我們查看的是文本的一小部分,看看它是否能夠和Regex匹配。但在這裡,只有考慮了整行文本之後我們才能可靠地判斷出哪些內容位於引號之內。

  下面是一個說明該問題的例子。從某個文字檔隨意抽取半行內容,得到:1, 沙灘, 黑色, 21, ', 狗, 貓, 鴨子, ', 。在這個例子中,因為“1”的左邊還有其他資料,要解析清楚它的內容是極其困難的。我們不知道這個資料片斷的前面有多少單引號,從而也就無法判斷哪些字元位於引號之內(在引號之內的文本解析時不能分割)。如果這個資料片斷之前有偶數個(或者沒有)單引號,那麼“', 狗, 貓, 鴨子, '”是用引號界定的字串且不可分割。如果前面的引號數量是奇數,那麼“1, 沙灘, 黑色, 21, '”是某個字串的結束部分且不可分割。

  因此,Regex必須分析整行文本,全面考慮出現了多少引號才能確定字元是處在引號對的內部還是外部,即:,(?=([^']*'[^']*')*(?![^']*'))。這個Regex首先找到一個引號,然後繼續尋找並保證逗號後面的單引號數量或者是偶數、或者是0。該Regex以下面這個判斷為基礎:如果逗號後面的單引號數量是偶數,那麼這個逗號位於字串之外。下表給出了更詳細的說明:

, 尋找一個逗號
(?= 繼續向前尋找以匹配下面這個模式:
( 開始一個新的模式
[^']*' [非引號字元]0個或者多個,然後是一個引號
[^']*'[^']*) [非引號字元]0個或者多個,然後是一個引號。結合前面的內容之後它匹配引號對
)* 結束模式並匹配整個模式(引號對)0次或者多次
(?! 向前尋找,排除此模式
[^']*' [非引號字元]0個或者多個,然後是一個引號
) 結束模式

  下面是一個VBScript函數,它接受一個字串參數,根據字串中的逗號分隔字元、單引號限定符分割字串,返回結果數組:

Function SplitAdv(strInput)
Dim objRE
Set objRE = new RegExp

' 設定RegExp對象
objRE.IgnoreCase = true
objRE.Global = true
objRE.Pattern = ",(?=([^']*'[^']*')*(?![^']*'))"

' Replace方法用chr(8)替換我們要用到的逗號,chr(8)即\b
' 字元,\b在字串中出現的可能極為微小。
' 然後我們根據\b把字串分割儲存到數組
SplitAdv = Split(objRE.Replace(strInput, "\b"), "\b")
End Function

  總而言之,用Regex解析文本資料檔案具有高效、縮短開發時間的優點,能夠節省大量分析檔案、根據複雜的條件提取有用資料的時間。在一個迅速發展的環境中仍會有許多傳統的資料可資利用,掌握如何構造高效的資料分析常式將是一種寶貴的技能。

   四、字串替換

  在最後一個例子中我們要看看VBScriptRegex的替換功能。ASP經常用於動態地格式化從各種資料來源獲得的文本。利用VBScriptRegex的強大功能,ASP能夠動態地改變匹配的複雜文本。通過加入HTML標記反白部分單詞就是一種常見的應用,比如反白搜尋結果中的搜尋關鍵詞。

  為說明實現方法,下面我們來看一個反白字串中所有“.NET”的例子。這個字串可以從任何地方獲得,比如資料庫或者其他Web網站。

<%
Set regEx = New RegExp
regEx.Global = true
regEx.IgnoreCase = True

' Regex模式,
' 尋找任何結尾為“.NET”的單詞或者URL。
regEx.Pattern = "(\b[a-zA-Z\._]+?\.NET\b)"

' 用於測試替換功能的字串
strText = "微軟建立了一個新網站www.ASP.NET。"

' 調用Regex的Replace方法
' $1表示把匹配的文本插入當前位置
Response.Write regEx.Replace(strText, _
"<b style='color: #000099; font-size: 18pt'>$1</b>")
%>

  這個例子中有幾個重要的地方必須注意。整個Regex被放入了一對圓括弧中,它的作用是截取所有匹配的內容供以後使用,這些內容在替換文本中通過$1引用。類似的截取每次替換可以使用多達9個,分別通過$1到$9引用。Regex的Replace方法和VBScript本身的Replace函數不同,它只需要兩個參數:被搜尋的文本,替換用的文本。

  在這個例子中,為了反白搜尋到的“.NET”字串,我們用粗體標記以及其他樣式屬性來包圍這些字串。使用這種搜尋和替換技術,我們能夠方便地為網站搜尋程式加上反白搜尋關鍵詞的功能,或者自動為頁面中出現的關鍵詞加上指向其他頁面的連結。

   結束語

  希望本文介紹的幾種Regex技巧對你在何時、如何應用Regex有所啟發。雖然本文的例子用VBScript編寫,但在ASP.NET中Regex同樣也大有用武之地,它是伺服器端控制項表單檢驗的主要機制之一,而且通過System.Text.RegularExpressions命名空間匯出到了整個.NET架構之中。



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。