1 of 25

字串樣式的表示法

2 of 25

Regular Expression 可以做什麼?

  • 比對某種樣式的字串
    • 搜尋 Hello ?

  • 比對樣式可以幹嘛?
    • 驗證是否與樣式相同
    • 搜尋
      • 搜尋所有 H 開頭 o 結尾的字?
  • 搜尋到了可以幹嘛?
    • 取代
      • 把 Heello 或 Heeeello 或 Heeeeeeeello 一次換成 Hello?

或是更複雜的需求

RE 可以輕鬆辦到

3 of 25

哪裡可以用 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, …

4 of 25

Visual Studio 的 Regex 支援

5 of 25

vim 中的 Regexp 支援

6 of 25

Regexp 比對符號規則

  • 有一系列的中介字符 (metacharactor 或 metasymbol)提供特殊比對功能。
    • . | ( ) [ ] { } ^ $ * + ? \(可能是 postfix, prefix, infix)
  • 剩下的皆為一般字符,皆比對自己。
    • hello 比對 hello
  • 若要比對 metasymbol,則需用 \ 來跳脫(Escape)
    • 比對 | 需使用 \|
    • 比對 [ 需使用 \[

7 of 25

任意字元

  • '.' 能比對所有字符,除了'\n' 以外。
    • (可透過一些 flag 影響 '.' 是否比對 '\n')

  • 'G.' 比對所有 'G' 跟著一個任意字元
    • 符合 'Ga', 'GG', 'G#', 'G[', 'G.'
  • 'a.b' 比對 'a' 和 'b' 中間夾著一個任意字元
    • 符合 'aab', 'a)b', 'a-b'
    • 不符合 'ab'

. 一定要比對到一個字元

8 of 25

比對 Metasymbol

  • 如果真要比對 '.'需用 '\.'

Regexp

Matches

Doesn't match

a.b

axb

abc

a\.b

a.b

axb

9 of 25

字符集

  • [abc] 比對個 a 或 b 或 c
  • [a-z] 比對任個 a, b, c, …, z 字符

  • [^A-Za-z] �比對任個字符不屬於 A~Z 和 a~z 之中

Regexp

Matches

Doesn't match

a[a-z]b

acb, abb

aCb, a2b, ab

a[^a-z]b

a@b, a2b

acb, ab

[Jj][Oo][Ee]

Joe,jOE

je,jo,jeo

[] 也一定要比對到一個字元

10 of 25

樣式重複的出現

  • '*' 表示前一個單元樣式出現零次多次

  • 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

* 可以代表 零次!!

11 of 25

樣式重複的出現

  • '+' 表示前一個單元樣式出現一次多次
    • ab+c 能比對 abc, abbbc 不能比對 ac
    • 0+10 能比對 010, 0000010 不能比對 10
  • '?' 表示前一個單元樣式出現一次零次
  • '{1,3}' 出現 1 ~ 3 次
  • '{1,}' 出現一次以上(等於 +)
  • '{,3}' 出現三次以內(包含 0 次)

12 of 25

在 shell 下使用 grep

$ grep [a-z][0-9]+ file 錯!

$ grep '[a-z][0-9]+' file 對!

grep regexp files …

cat files … | grep regexp

若不用 ' ' 框起來,會被 shell 用於比對檔案名稱,而先行處理掉!

$ ls # 目錄中有這些檔案

a0+ aa b32 b9+

$ echo [a-z][0-9]+ # 樣式被處理掉了

a0+ b9+ # 原本預期印出 [a-z][0-9]+

13 of 25

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 是 .*

14 of 25

Grouping

  • * + ? {} 等皆表示前一「單元樣式」的數量
  • 如何組成一個更大的「單元樣式」?
    • 不只是一個字符,或是 [a-z] 等字符集

Regexp

Matches

Doesn't match

a(bc)*d

ad, abcd, abcbcd

acd, acbd

([0-9]0)+

20, 2010, 102030

11, 2120

15 of 25

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>

16 of 25

貪心的量詞

  • * + ? { } 都很貪心,能比對多長就多長。
    • 'a.*b' 比對字串 aaaaaaaabaaaaaaaaabaaaaa
    • 會比對到 aaaaaaaabaaaaaaaaab
    • 並非 aaaaaaaab
  • 貪心會影響什麼?
    • 搜尋,影響效率
    • 取代,影響效率和正確性
  • 用量詞加上 ? 可以讓他們不貪心
    • 'a.*?b'
    • (grep, sed, vi 不支援)
    • (emacs, python, perl 支援)

17 of 25

定位點

  • ^ 定位行頭
  • $ 定位行尾

  • '^a.*b$' 任何以 a 開頭 b 結尾的行

  • regexp 預設以行為單位搜尋
  • 也可設定 flag 使 regexp 將整篇文章當作連續的字串搜尋。同時 '.' 可比對 '\n'

18 of 25

或 |

  • [] 僅能表示單一字元的候選比對
    • [a-c] a 或 b 或 c
    • [.()] . 或 ( 或 )

  • | 長字串的候選
    • (hello|hi) 比對 hello, hi
    • (a[0-4]|b[5-9]) 比對 a0, a3, b6, b7

19 of 25

眾多延伸的 regexp 語法

  • 定位點 \b \< \> \Z \A…
  • 字符集 \w \d \s [:alpha:]…
  • 環顧 (?<=…) (?=…) (?!...) (?<!...)…
  • group 但不 memory (?: …)…
  • flag 設定 (?imsxuL)…
  • 註解 (?#...)…

20 of 25

每個 Tool 的 Regex 不盡相同

  • 目標:搜尋單字開頭是 os 的 word。
    • grep 使用 \bos
    • sed 使用 \<os

$ echo -e 'hh os hh\nhhoshh\nhhos hh\nhh oshh'

hh os hh

hhoshh

hhos hh

hh oshh

$ echo -e 'hh os hh\nhhoshh\nhhos hh\nhh oshh' | grep '\bos'

hh os hh

hh oshh

$ echo -e 'hh os hh\nhhoshh\nhhos hh\nhh oshh' | sed -ne '/\<os/p'

hh os hh

hh oshh

同 vi

21 of 25

要不要 Escape metasymbol

在 grep 中,若要 group 需用 \( \)

在 egrep 中,若要 group 用 ()

  • Tool 之間不僅延伸語法不同,基本 metasymbols 也經常存在需不需要 Escape 的差異。
    • 如 | 還是 \|
    • ( 還是 \(
    • + 還是\+

22 of 25

Tool 這麼多,要如何查詢語法

  • 網路查
    • Scripting Language 的Library Reference
    • Tool 的 Manual
    • 教學網頁
  • 書上查
    • 各個 Tool 的書籍
      • O'Reilly Programming Perl
    • 整理好語法的書籍。
      • O'Reilly Regular Expression Packet Reference

說明就在我們手邊

  • vim
    • :help pattern.txt
  • perl
    • perldoc perlre
  • python
    • import re
    • help(re)
  • man -k regex
  • man -k grep

23 of 25

Regex 並非萬能

  • Regex 提供簡便的方式表示字串樣式。常常一行勝百行。
  • 但有些格式對 Regex 難如登天,用程式邏輯處理卻相當容易。

<div>

<div>

<div>

</div>

</div>

</div>

<div>

<div>

</div>

</div>

目標

<div>.*</div>

<div>.*?</div>

巢狀格式,對 Regex 很難,�但用程式寫卻能輕鬆解決

24 of 25

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 \;

_____

< FIN >

-----

\ ^__^

\ (oo)\_______

(__)\ )\/\

||----w |

|| ||

25 of 25

參考

  • 部分範例取自 �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