250 likes | 522 Views
字串樣式的表示法. Regular Expression. Regular Expression 可以做什麼?. 嫩. 比對某種 樣式 的字串 搜尋 Hello ? 比對樣式可以幹嘛? 驗證 是否與樣式相同 搜尋 搜尋所有 H 開頭 o 結尾的字? 搜尋到了可以幹嘛? 取代 把 Heello 或 Heeeello 或 Heeeeeeeello 一次換成 Hello ?. RE 可以輕鬆辦到. 或是更複雜的需求. 哪裡可以用 Regular Expression. Unix Tools grep, sed, awk , ed
E N D
字串樣式的表示法 Regular Expression
Regular Expression 可以做什麼? 嫩 • 比對某種樣式的字串 • 搜尋 Hello ? • 比對樣式可以幹嘛? • 驗證是否與樣式相同 • 搜尋 • 搜尋所有 H 開頭 o 結尾的字? • 搜尋到了可以幹嘛? • 取代 • 把 Heello 或 Heeeello 或 Heeeeeeeello 一次換成 Hello? RE 可以輕鬆辦到 或是更複雜的需求
哪裡可以用 Regular Expression • Unix Tools • grep, sed, awk , ed • Scripting Language • php, perl, python, ruby, PowerShell, JavaScript, VBScript, Visual Basic, XPath, Tcl, … • Database • MySQL, Oracle, PostgreSQL, … • Editor • Emacs, vi, Editor in Visual Studio, …
Regexp 比對符號規則 • 有一系列的中介字符 (metacharactor 或 metasymbol)提供特殊比對功能。 • . | ( ) [ ] { } ^ $ * + ? \(可能是 postfix, prefix, infix) • 剩下的皆為一般字符,皆比對自己。 • hello比對 hello • 若要比對 metasymbol,則需用 \來跳脫(Escape) • 比對 |需使用 \| • 比對 [需使用 \[
任意字元 • '.' 能比對所有字符,除了'\n' 以外。 • (可透過一些 flag 影響 '.' 是否比對 '\n') • 'G.' 比對所有 'G' 跟著一個任意字元 • 符合 'Ga', 'GG', 'G#', 'G[', 'G.' • 'a.b' 比對 'a' 和 'b' 中間夾著一個任意字元 • 符合 'aab', 'a)b', 'a-b' • 不符合 'ab' . 一定要比對到一個字元
比對 Metasymbol • 如果真要比對 '.'需用 '\.'
字符集 [] 也一定要比對到一個字元 • [abc]比對單個 a 或 b 或 c • [a-z]比對任一個 a, b, c, …, z 字符 • [^A-Za-z]比對任一個字符不屬於 A~Z 和 a~z 之中
樣式重複的出現 • '*' 表示前一個單元樣式出現零次到多次 • ab*c能比對 ac, abc, abbbbc • a[fgh]*b能比對 ab, afb, aghffgghfgb • Hi Jo.* 能比對 Hi Jo, Hi Joseph, Hi Johnr2343#@(. • 1[0-9]*0能比對 10, 110, 1203900, 10000 * 可以代表 零次!!
樣式重複的出現 • '+' 表示前一個單元樣式出現一次到多次 ab+c能比對 abc, abbbc 不能比對 ac 0+10能比對 010, 0000010 不能比對 10 • '?' 表示前一個單元樣式出現一次或零次 • '{1,3}' 出現 1 ~ 3 次 • '{1,}' 出現一次以上(等於 +) • '{,3}' 出現三次以內(包含 0次)
在 shell 下使用 grep grep regexp files … cat files … | grep regexp $ grep [a-z][0-9]+ file 錯! $ grep '[a-z][0-9]+' file 對! 若不用 ' ' 框起來,會被 shell 用於比對檔案名稱,而先行處理掉! $ ls # 目錄中有這些檔案 a0+ aa b32 b9+ $ echo [a-z][0-9]+ # 樣式被處理掉了 a0+ b9+ # 原本預期印出 [a-z][0-9]+
Shell 提供的檔名比對並非 regexp $ ls hello.txt a01.jpg a02.jpg a03.jpg a04.jpg aa b32.jpg aa.txt $ ls a[0-9][0-9] ls: cannot access a[0-9][0-9]: No such file or directory $ ls a[0-9][0-9]* a01.jpg a02.jpg a03.jpg a04.jpg * 不代表次數,是萬用字符相對於 regexp 是 .*
Grouping • * + ? {} 等皆表示前一「單元樣式」的數量 • 如何組成一個更大的「單元樣式」? • 不只是一個字符,或是 [a-z] 等字符集
Grouping and Memory • 任何使用 ( ) 框起來的東西,都會被記憶 • \1 代表第一個被 () 記憶的字串 • \2 代表第二個被 () 記憶的字串 • 最多到 \9(超過怎麼辦?有些延伸命名的方法,但不統一) • (\0 代表整個比對結果,很少用) • '([a-z]+) \1' • 能比對 'Hello Hello', 'me me' • 可透過一些 flag 要求 regexp 管不管大小寫 • '(b(c))\2\1' 能比對 bccbc • '<([a-z][a-z0-9]*)[^>]*>[^<]*</\1>' • 比對任意 XML, HTML 最內層的 tag • <a href="../cc.html">CC</a>
貪心的量詞 • * + ? { } 都很貪心,能比對多長就多長。 • 'a.*b' 比對字串 aaaaaaaabaaaaaaaaabaaaaa • 會比對到 aaaaaaaabaaaaaaaaab • 並非aaaaaaaab • 貪心會影響什麼? • 搜尋,影響效率 • 取代,影響效率和正確性 • 用量詞加上 ?可以讓他們不貪心 • 'a.*?b' • (grep, sed, vi 不支援) • (emacs, python, perl 支援)
定位點 • ^ 定位行頭 • $ 定位行尾 • '^a.*b$' 任何以 a 開頭 b 結尾的行 • regexp 預設以行為單位搜尋 • 也可設定 flag 使 regexp 將整篇文章當作連續的字串搜尋。同時 '.' 可比對 '\n'
或 | • [] 僅能表示單一字元的候選比對 • [a-c] a 或 b 或 c • [.()] . 或 ( 或 ) • | 長字串的候選 • (hello|hi) 比對 hello,hi • (a[0-4]|b[5-9]) 比對 a0, a3,b6, b7
眾多延伸的 regexp 語法 • 定位點 \b \< \> \Z \A… • 字符集 \w \d \s [:alpha:]… • 環顧 (?<=…) (?=…) (?!...) (?<!...)… • group 但不 memory (?: …)… • flag 設定 (?imsxuL)… • 註解 (?#...)… • …
每個 Tool 的 Regex 不盡相同 • 目標:搜尋單字開頭是 os的 word。 • grep 使用 \bos • sed 使用 \<os 同 vi $echo -e 'hhoshh\nhhoshh\nhhoshh\nhhoshh' hhoshh hhoshh hhoshh hhoshh $echo -e 'hhoshh\nhhoshh\nhhoshh\nhhoshh' | grep '\bos' hhoshh hhoshh $echo -e 'hhoshh\nhhoshh\nhhoshh\nhhoshh' | sed -ne '/\<os/p' hhoshh hhoshh 一份簡略的 Regexp 比較表 http://www.greenend.org.uk/rjk/2002/06/regexp.html
要不要 Escape metasymbol 在 grep 中,若要 group 需用 \( \) 在 egrep 中,若要 group 用 () • Tool 之間不僅延伸語法不同,基本 metasymbols 也經常存在需不需要 Escape 的差異。 • 如 | 還是 \| • ( 還是 \( • + 還是\+
Tool 這麼多,要如何查詢語法 • 說明就在我們手邊 • vim • :help pattern.txt • perl • perldoc perlre • python • import re • help(re) • man -k regex • man -k grep • 網路查 • Scripting Language 的Library Reference • Tool 的 Manual • 教學網頁 • 書上查 • 各個 Tool 的書籍 • O'Reilly Programming Perl • 整理好語法的書籍。 • O'Reilly Regular Expression Packet Reference 一份簡略的 Regexp 比較表 http://www.greenend.org.uk/rjk/2002/06/regexp.html
Regex 並非萬能 • Regex 提供簡便的方式表示字串樣式。常常一行勝百行。 • 但有些格式對 Regex 難如登天,用程式邏輯處理卻相當容易。 <div> <div> <div> … </div> </div> </div> <div> <div> </div> </div> … 目標 <div>.*?</div> 巢狀格式,對 Regex 很難,但用程式寫卻能輕鬆解決 <div>.*</div>
_____ < FIN > ----- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || Cowsay Shell Script for • $ for cow in $(ls /usr/share/cowsay/cows/) • > do cowsay -f $cow moo • > done xargs • $ls /usr/share/cowsay/cows/ | xargs -I cow -n1 cowsay -f cow moo find • $ find /usr/share/cowsay/cows/ -exec cowsay -f {} moo \;
參考 • 部分範例取自 Pattern Matching and Regular Expressions sed & awk (Intro to Unix Spring 2000 Pattern Matching) http://www.cs.rpi.edu/~hollingd/introunix/lectures/regexp.ppt • O'Reilly Programming Perl