Regular Expressions

用一行字
去找一堆字

不是找某一個詞,是形容「我要找長得像這樣的東西」,然後讓電腦自己去撈。

\d+

意思是:一個以上的數字。

民國 114 年 3 月,共 27 人報名,錄取 12 名。

你沒有告訴它 114、3、27、12 是什麼。你只說了「數字,一個以上」。

入門只要三個問題。

要找什麼樣的字元、要幾個、要在哪裡。剩下的都是變化。

哪一類字元?
\d任何數字
\s空白
[abc]a、b、c 之中的一個
[a-z]a 到 z 之中的一個
.任何字元
要幾個?
+一個以上
*零個以上(可以沒有)
?有或沒有都行
{3}剛好三個
{2,4}兩到四個
在哪裡?
^一行的開頭
$一行的結尾
( )框起來,之後可以回頭引用
|或者

組起來就是這樣。

用這三種零件描述一支台灣手機號碼:

09\d{2}-?\d{3}-?\d{3}
09就是這兩個字,一字不差
\d{2}接著剛好兩個數字
-?一個橫線,有沒有都可以
\d{3}三個數字
-?再一個可有可無的橫線
\d{3}最後三個數字
✓0912-345-678
✓0912345678
×09123456
×0212345678

自己試。改一個字就看得出差別。

上面打規則,下面貼文字,符合的會即時亮起來。打錯了它會告訴你哪裡壞掉。

■ 字元類 ■ 數量 ■ 位置 ■ 群組 ■ 照字面找

幾乎每個人都會踩的第一個坑。

.* 是「任何字元,越多越好」— 它會一路吃到最後,不會禮貌地停在第一個。

<.*> <a><b> → <a><b> 貪婪:整串一口吞掉。
<.*?> <a><b> → <a><b> 加個 ? 變不貪心:見好就收。

另外兩個。

但它有一件事永遠做不到。

regex 不會數數。它可以確認括號有沒有出現,卻沒辦法確認左右括號是不是一樣多、有沒有正確配對。

( ( ( ) ) )
( ( )

要數對,得記得「現在欠幾個右括號」— 而那份記憶可以無限長。regex 的機器裡只有固定數量的狀態,裝不下。

所以:巢狀括號、程式碼、HTML、XML,都不能用 regex 正確剖析。這不是寫得不夠好,是理論上不可能。

regex 很小,小到裝不下「數數」。
但它也就是因為這麼小,才能跑得那麼快。