4-7 龠牌pA洏

如果我們要同時比對數個通用式,可以使用「|」將他們串起來,而達到「或」(OR)的邏輯運算效果,例如,如果我們要同時比對信用卡號碼、身份證字號、電話號碼,可參見下列範例:

Example 1: 04-通用運算式/regExp16.mstring = '1234-5678-9012-3456 and A123456789 and 5715131'; pattern = '\d{4}-\d{4}-\d{4}-\d{4}|[A-Z]\d{9}|\d{7}'; [start, finish] = regexp(string, pattern); fprintf('Matched substrings:\n'); for i=1:length(start) fprintf('\t%d: %s\n', i, string(start(i):finish(i))); endMatched substrings: 1: 1234-5678-9012-3456 2: A123456789 3: 5715131

若是要進行 OR 運算的通用式有共通的部分,我們就需要使用小括弧來進行更明確的規範,例如下列範例,可以同時比對 Chapter 和 Section,以及後續的數字:

Example 2: 04-通用運算式/regExp17.mstring = 'I like Chapter 12, particularly Section 4!'; pattern = '(Chapter|Section) [1-9]\d?'; [start, finish] = regexp(string, pattern); fprintf('Matched substrings:\n'); for i=1:length(start) fprintf('\t%d: %s\n', i, string(start(i):finish(i))); endMatched substrings: 1: Chapter 12 2: Section 4

小括弧也可以用來進行重複字串的比對,詳見前一節的說明。

除了用來規範比對的方式外,小括弧還有一個非常重要的功能,就是可以將對應於小括弧的子字串傳回來,非常適用於特定子字串的抽取。這部分的資訊是經由 regexp 指令的第三個輸出變數所傳回,例如:

Example 3: 04-通用運算式/regExp20.mstring = 'I bet there is a bat on the boat'; pattern = 'b(\w*)t'; [start, finish, token] = regexp(string, pattern); fprintf('There are %d matched substrings:\n', length(start)); for i=1:length(start) fprintf('\t%d: matched="%s", token="%s"\n', i, ... string(start(i):finish(i)), string(token{i}(1):token{i}(2))); endThere are 3 matched substrings: 1: matched="bet", token="e" 2: matched="bat", token="a" 3: matched="boat", token="oa"

在上例中,token 就是由 b 和 t 所夾的字串。

通用式在使用「貪心比對」時,會採用「越左越貪」的原則,例如在使用通用式 'a(.*)b(.*)d' 來比對字串 'a--b---b----d' 時,左右邊的括弧會分別比對到 '--b---' 和 '----',而不是'--' 和 '---b----'。若要改變「越左越貪」的原則,可以使用問號來指定最小比對,請見下列範例:

Example 4: 04-通用運算式/regExp22.mstr = 'a--b---b----d'; pat1 = 'a(.*)b(.*)d'; % 「越左越貪」的比對 [start, finish, token] = regexp(str, pat1); fprintf('「越左越貪」的比對結果:\n'); for j=1:size(token{1},1) fprintf('\ttoken%d = "%s"\n', j, str(token{1}(j,1):token{1}(j,2))); end pat2 = 'a(.*?)b(.*)d'; % 利用問號來修正 [start, finish, token] = regexp(str, pat2); fprintf('利用問號來進行「最小比對」的結果:\n'); for j=1:size(token{1},1) fprintf('\ttoken%d = "%s"\n', j, str(token{1}(j,1):token{1}(j,2))); end「越左越貪」的比對結果: token1 = "--b---" token2 = "----" 利用問號來進行「最小比對」的結果: token1 = "--" token2 = "---b----"

使用小括弧來抽取所要的字串,是一個很有用的功能。我們可以利用此功能來抽取網頁的連結網址和連結文字,這在網頁搜尋引擎的製作上,是一個很重要的步驟,因為「網頁蒐集程式」(又稱為 Web Robot 或 Web Crawler)將網頁抓回來後,就是根據網頁內的連結網址,來決定下次要蒐集的網頁,如此依次(可根據 Depth-first Search 或 Breadth-first Search)反覆蒐集,就可以抓到很多網頁。例如在我們的範例程式中,有一個網頁檔案 regExp.htm,其內容如下:

<html> <body> List of important links: <ul> <li>Homepage of MathWorks: <a href="http://www.mathworks.com">MathWorks</a>. <li>Homepage of Roger Jang: <a href="http://www.cs.nthu.edu.tw/~jang">Roger Jang</a>. <li>Homepage of Google: <a href="http://www.google.com">Google</a>. </ul> </body> </html>

以網頁瀏覽器開啟此檔案,得到的畫面如下:

利用 regexp 指令所傳回來的第三個輸出變數,我們可以輕易地抓出此網頁的連結網址和連結文字,請見下列範例:

Example 5: 04-通用運算式/linkExtract.mfileName = 'regExp.htm'; string=fileread(fileName); pattern = '<a href="(.*?)">(.*?)</a>'; [start, finish, token] = regexp(string, pattern); fprintf('由檔案 "%s" 抽取出 %d 個連結::\n', fileName, length(start)); for i=1:length(start) fprintf('\t%d: 連結文字:"%s", 連結網址:"%s"\n', ... i, string(token{i}(2,1):token{i}(2,2)), string(token{i}(1,1):token{i}(1,2))); end

在上述範例中,特別要注意的是,小括弧內部的問號是代表「最小比對」,表示如果有兩種可能的比對情況,那麼我們會選擇讓比對到的字串越短越好,以免發生錯誤。

Hint
使用類似的方法,也可以抽取網頁中的電子郵件帳號,這也是一般 Robot 程式的主要任務之一。


MATLAB程式設計:進階篇