張智星 jang@cs.nthu.edu.tw http://www.cs.nthu.edu.tw/~jang 清大資工系 多媒體檢索實驗室 MATLAB 程式設計入門篇 通用運算式 張智星 jang@cs.nthu.edu.tw http://www.cs.nthu.edu.tw/~jang 清大資工系 多媒體檢索實驗室
4-1 通用運算式的基本介紹 通用運算式(Regular Expressions)最早出現在 UNIX 的文字編輯程式,例如 ed、vi ,也常被用在以 UNIX 為基礎的程式語言,例如 Perl 等。近年來在 Web 上使用的 JavaScript / JScript 以及 VBScript 也加入了通用運算式的功能。 通用運算式的終極目標就是「用簡單的符號來代表複雜的字串,以便進行特定字串的比對、代換及抽取」。
4-2 通用式的基本用法 使用 regexp 指令比對字串,可找出某一個特定型態的字串在另一個字串的出現位置。 例如,如果要找出「love」在一個字串「Love me tender, love me sweet, never let me go」出現的位置,可用下列程式碼: 範例4-1: regExp01.m 回傳結果為: startIndex = 17 代表「love」在 string 變數所出現的位置是 17。 string = 'Love me tender, love me sweet, never let me go'; pattern = 'love'; startIndex = regexp(string, pattern)
4-2 通用式的基本用法 若要進行「大小寫均可」(Ignore Cases)的比對,則可以使用 regexpi 指令 : 範例4-2: regExp02.m 回傳結果為:startIndex = 1 17 代表「Love」和「love」在 string 變數所出現的位置分別是 1 和 17。 string = 'Love me tender, love me sweet, never let me go'; pattern = 'love'; startIndex = regexpi(string, pattern)
4-3方括弧的使用 我們可以使用方括弧([])來列舉所要比對的字元,可見下列範例: 範例4-4: regExp10.m string = 'I bet there is a bat on the boat'; pattern = 'b[aeiou]t'; [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))); end 回傳結果為:Matched substrings: 1: bet 2: bat
4-3方括弧的使用 有關方括弧的使用,我們在下面做一個列表整理與說明: 通用式 說明及範例 比對不成立之字串 [13579] 包含 "1" 或 "3" 或 "5" 或 "7" 或 "9" 的字串,例如:"a3b", "1xy" "y2k" [0-9] 含數字之字串 不含數字之字串 [a-z0-9] 含數字或小寫字母之字串 不含數字及小寫字母之字串 [a-zA-Z0-9] 含數字或字母之字串 不含數字及字母之字串 b[aeiou]t "bat", "bet", "bit", "bot", "but" "bxt", "bzt" [^0-9] 不含數字之字串 (若要比對 ^,請使用 \^) [^aeiouAEIOU] 不含母音之字串 (若要比對 ^,請使用 \^) 含母音之字串 [^\^] 不含 "^" 之字串,例如 "xyz", "abc" "xy^", "a^bc"
4-4 特定字元 有些通用式會常被用到,因此已被定義為特定字元,以簡化整體通用式,這些字元可列表說明如下: 通用式的特定字元 說明 等效的通用式 \d 數字 [0-9] \D 非數字 [^0-9] \w 數字、字母、底線 [a-zA-Z0-9_] \W 非 \w [^a-zA-Z0-9_] \s 空白字元 [ \r\t\n\f] \S 非空白字元 [^ \r\t\n\f] . 任一個字元,但不包含換行字元(\n) 無
4-4 特定字元 我們可以用「\d」來比對由 0 到 9 的數字,並用「\D」來比對非數字。假設我們要找出「兩個非數字夾一個數字」的子字串,可使用「\D\d\D」。 範例4-7: regExp04.m string = 'Some terms: RU486, Y2K, 900GHz, B2B, B2C'; pattern = '\D\d\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))); end 回傳結果為: Matched substrings: 1: Y2K 2: B2B 3: B2C
4-5 定位符號 在通用式裡,最常用的定位符號就是 ^ 和 $,其中 ^ 代表一個字串的開始位置,因此 ^xy 代表「以 xy 開始的字串」;而 $ 代表一個字串的結束位置,因此 xy$ 「代表以 xy 結束的字串」。 範例4-9: regExp14.m str1 = 'Chapter 5 is my favorite'; str2 = 'I like Chapter 2'; pat = '^Chapter'; fprintf('regexp(''%s'', ''%s'') = %d\n', str1, pat, regexp(str1, pat)); fprintf('regexp(''%s'', ''%s'') = %d\n', str2, pat, regexp(str2, pat)); 回傳結果為: regexp('Chapter 1 is my favorite', '^Chapter') = 1 regexp('I like Chapter 1', '^Chapter') =
4-5 定位符號 以下是對於定位符號的列表與整理: 通用式 說明及範例 比對不成立之字串 ^xy 以 "xy" 開始的字串,例如 "xyz", "xyab" (若要比對 ^,請使用 \^) "axy", "bxy" xy$ 以 "xy" 結尾的字串,例如 "axy", "abxy" (若要比對 $,請使用 \$) "xya", "xyb"
4-6 字元與字串的重複 我們也可定義字元的重複次數,整理如下: 正規表示法 說明 a? 零或一個 a (若要比對? 字元,請使用 \?) a.{5}b a 和 b中間夾五個(非換行)字元
4-6 字元與字串的重複 使用上表與字元重複次數相關的特殊符號,我們可以從字串「I like Chapter 2, Chapter 10, and Chapter 25 of this book!」抓出「Chapter 2」、「Chapter 10」,以及「Chapter 25」 範例4-10: regExp08.m string = 'I like Chapter 2, Chapter 10, and Chapter 25 of this book!'; pattern = 'Chapter [1-9][0-9]?'; [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))); end 回傳結果為:Matched substrings: 1: Chapter 2 2: Chapter 10 3: Chapter 25
4-7 選項與小括弧的使用 如果同時比對數個通用式,可使用「|」來他們串起來,而達到「或」(OR)的邏輯運算效果。如,我們可同時比對信用卡號碼、身份證字號、電話號碼 。 範例4-16: regExp16 .m string = '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))); end 回傳結果為:Matched substrings: 1: 1234-5678-9012-3456 2: A123456789 3: 5715131
4-7 選項與小括弧的使用 小括弧還有一個非常重要的功能,就是可以將對應於小括弧的子字串傳回來,非常適用於特定子字串的抽取。 範例4-18: regExp20 .m string = '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))); end 回傳結果為:There are 3 matched substrings: 1: matched="bet", token="e“ 2: matched="bat", token="a" 3: matched="boat", token="oa" 在上例中,token 就是由 b 和 t 所夾的字串。
4-8 字串的代換 利用通用式來進行字串的代換,主要的指令是 regexprep。如,若要將所有「b 和 t 中間至少夾一個母音」的字串代換為 xxx。 範例4-21: regExpRep01 .m str = 'I bet there is a bat in the boat!'; pat = 'b[aeiou]+t'; newStr = regexprep(str, pat, 'xxx'); fprintf('%s\n', newStr); 回傳結果為: I xxx there is a xxx in the xxx!