我們也可定義字元的重複次數,整理如下:
通用表示法 說明
a? 零或一個 a(若要比對? 字元,請使用 \?)
a+ 一或多個 a(若要比對+ 字元,請使用 \+)
a* 零或多個 a(若要比對* 字元,請使用 \*)
a{4} 四個 a
a{5,10} 五至十個 a
a{5,} 至少五個 a
a{,3} 至多三個 a
a.{5}b a 和 b中間夾五個(非換行)字元
使用上表與字元重複次數相關的特殊符號,我們可以從字串「I like Chapter 2, Chapter 10, and Chapter 25 of this book!」抓出「Chapter 2」、「Chapter 10」,以及「Chapter 25」,請見下列範例:
Example 1: 04-通用運算式/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
若要抓出信用卡號碼,可見下列範例:
Example 2: 04-通用運算式/regExp12.m string = 'My credit number is "1234-5678-9012-3456".';
pattern = '\d{4}-\d{4}-\d{4}-\d{4}';
[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
如果要比對身份證字號,可用下列範例:
Example 3: 04-通用運算式/regExp05.m string = 'My Id number is F123765431';
pattern = '[A-Z]\d{9}';
start = regexp(string, pattern) start =
17
此回傳結果代表 F123765431 在 string 變數的開始位置。在上述範例中, [A-Z] 代表由 A 至 Z 的所有可能英文字母,\d 代表由 0 至 9 的數目字(事實上也可以寫成 [0-9]),{9} 則代表需要有九個數目字,因此 「[A-Z]\d{9}」 就代表可以比對身份證字號的通用式。
Hint 事實上,身份證字號本身就有內在的編碼規則,這些規則和使用者的性別有關,還包含一個檢查碼,並非簡簡單單地由一個英文字母加上九個數字所構成。有關於身份證字號的編碼規則,可以在網路的搜尋引擎(例如 www.google.com)上查到很多相關說明。
若要在一個字串中,找出「在 b 與 t 中間夾二或三個母音的子字串」,可見下列範例:
Example 4: 04-通用運算式/regExp09.m string = 'bt bat bet ban bit boat beet berp boaet baeiout';
pattern = 'b[aeiou]{2,3}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: boat
2: beet
3: boaet
我們也可以利用小刮號,進行重複字串的比對。例如前面提到的信用卡號碼,通用式可以寫成「\d{4}-\d{4}-\d{4}-\d{4}」,也可以利用小括弧寫成「(\d{4}-){3}\d{4}」(\d{4}- 重複三次,再加上 \d{4}),請見下列範例:
Example 5: 04-通用運算式/regExp18.m string = 'Two cards: 1234-5678-9012-3456 and 0987-6543-2109-8765';
pattern = '(\d{4}-){3}\d{4}';
[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: 0987-6543-2109-8765
特別要注意的是,在通用式的比對過程中,所採用的方法是「最大比對(Maximal Match)或是」「貪心比對」(Greedy Match),因此會盡量「貪」到越多的字元越好,例如,若使用通用式 'foo.*bar' 來比對字串 'The food is under the bar in the barn.',所比對到的是長字串 ‘food is under the bar in the bar’,而不是另一個符合比對標準的短字串 ‘food is under the bar’。若要使通用式進行極小比對(Minimal Match),也就是在符合比對的條件下,選擇最短的字串,那麼就要在星號之後加上問號,請見下列範例:
Example 6: 04-通用運算式/regExp19.m string = 'The food is under the bar in the barn.';
pattern1 = 'foo.*bar';
[start, finish] = regexp(string, pattern1);
fprintf('\tGreedy match: %s\n', string(start:finish));
pattern2 = 'foo.*?bar';
[start, finish] = regexp(string, pattern2);
fprintf('\tMinimal match: %s\n', string(start:finish)); Greedy match: food is under the bar in the bar
Minimal match: food is under the bar
Hint 各位讀者可以發現,問號在通用式的意義是和上下文相關(Context Dependent)的,可以分兩類情況來說明:
如果問號接在一般字元之後,代表「比對前一個字元零次或一次」。 如果問號接在星號或加號之後,代表「極小比對」。
MATLAB程式設計:進階篇