正則學習二三事
正則一直是我一大痛點,一直都想解決這個問題,但是奈何每次看到那麼多符號就發矇,所以就一直拖下去了。直到最近總是被別人問到如何在hql中使用rlike查詢符合特定規則的欄位,然後各種不會,結果被鄙視的一塌糊塗,無奈,這才靜下心來慢慢研究。
以前看正則就是一堆符號,代表各個意思,如\d表示數字,\d+表示一個或者多個連續數字,單看每個規則都可以理解,除了組合,但是實際使用時真的很難組織到一起。歸根結底還是因為對這些符號的理解不夠深入。所以正則還是得多寫,推薦一個線上練習的網站RegexGolf。好了,下面寫寫自己學習正則的一些總結吧,希望能夠幫助到別人,也幫助自己總結總結。
正則的基礎知識:
字面值
正則表示式由只代表自身的字面值和代表特定含義的元字元組成。 只代表自身的字面值指的是普通的字元,如abcde,特殊含義的元字元包括:字元 含義 \ 反斜線字元 \0n 帶有八進位制值 0 的字元 n (0 <= n <= 7) \0nn 帶有八進位制值 0 的字元 nn (0 <= n <= 7) \0mnn 帶有八進位制值 0 的字元 mnn(0 <= m <= 3、0 <= n <= 7) \xhh 帶有十六進位制值 0x 的字元 hh \uhhhh 帶有十六進位制值 0x 的字元 hhhh \t 製表符 (‘\u0009’) \n 新行(換行)符 (‘\u000A’) \r 回車符 (‘\u000D’) \f 換頁符 (‘\u000C’) \a 報警 (bell) 符 (‘\u0007’) \e 轉義符 (‘\u001B’) \cx 對應於 x 的控制符 字元類
字元類是字元在方括號中的集合。表示“找到集合裡任意一個字元“。例如:字元 含義 [abc] a、b 或 c(簡單類) [^abc] 任何字元,除了 a、b 或 c(否定) [a-zA-Z] a 到 z 或 A 到 Z,兩頭的字母包括在內(範圍) [a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](並集) [a-z&&[def]] d、e 或 f(交集) [a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](減去) [a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](減去) 從上表可以看出[]裡面可進行並集/交集/差集操作。對於字元範圍是根據ASCII值的大小來的,例如[A-z]也是可以的,甚至能夠匹配[,但是完全不建議如此使用,推薦使用的字元範圍:[0-9]/[a-z]/[A-Z]。
字元類還有一些預定義的字元類:字元 含義 . 任何字元(與行結束符可能匹配也可能不匹配) \d 數字:[0-9] \D 非數字: [^0-9] \s 空白字元:[ \t\n\x0B\f\r] \S 非空白字元:[^\s] \w 單詞字元:[a-zA-Z_0-9] \W 非單詞字元:[^\w] 使用上面的預定義字元類能夠更加方便的表示字元範圍。需要牢記。
注意: 區間是字元的區間,不是數字的區間。正則表示式[1-31]表示“找到一個1或一個2或一個3”,不是“找到一個從1到31的整數”。乘法器
字元 含義 X? X,一次或一次也沒有 X* X,零次或多次 X+ X,一次或多次 X{n} X,恰好 n 次 X{n,} X,至少 n 次 X{n,m} X,至少 n 次,但是不超過 m 次 X可以使一個普通字面值,如a+:一個或多個a,也可以是一個字元類,如[abc]{2},表示a/b/c後跟a/b/c。
值得注意的是優先選擇更長的匹配,因為乘法器是貪婪的。如果你輸入的文字是I had an aaaaawful day,該正則表示式就會在aaaaawful中匹配到aaaaa。不會在第三個a後就停止匹配。
乘法器是貪婪的,但它不會忽略一個更好的匹配。如果你的輸入文字為I had an aaawful daaaaay,之後這個正則表示式會在第一次的匹配中於aaawful找到aaa。只有在你說“給我找到另一個匹配”的時候,它才會繼續搜尋然後在daaaaay中找到aaaaa。
惰性:
正則表示式“.”表示“找到一個雙引號,接著找到儘可能多的字元,最後再找到一個雙引號”。注意一下被.匹配的內部字元,很可能包含多個雙引號。這通常不是非常有用。乘法器可通過追加問號(?)來實現惰性。“.?”*表示“匹配一個雙引號,跟著一個儘可能少的字元,再跟著一個雙引號”。分支
可以使用管道符號來實現匹配多種選擇。字元 含義 X|Y X或者Y 組合
可以使用圓括號來組合表示式。例:
在一週中找到一天,使用(Mon|Tues|Wednes|Thurs|Fri|Satur|Sun)day,這裡如果把小括號或者中括號,結果是完全不一樣的,因為中括號是字元類,即裡面的Mon並不是完全匹配Mon,而是隻要匹配M/o/n其中一個即可。
同時組合後面還可跟上乘法器,如:\w+(\s+\w+)*代表“找到一個或多個單詞,它們以空格隔開”。邊界
邊界分成:單詞邊界,行邊界,文字邊界- 單詞邊界
單詞邊界是一個單詞字元和非單詞字元之間的位置。記住,一個單詞字元是\w,它是[0-9A-Za-z_],一個非單詞字元是\W,也就是[^0-9A-Za-z_]。
文字的開頭和結尾總是當作單詞邊界。
輸入的文字it’s a cat有八個單詞邊界,分別為:文字開頭-i,t-‘,’-s,s-空格,空格-a,a-空格,空格-c,t-文字結尾。 - 行邊界
每一塊文字會分解成一個或多個行,用換行符分隔。
注意文字不是以換行符結束,而是以行結束。然而,任何行,包括最後一行,可以包含零個字元。
起始行位置是在一個換行符和下一行的第一個字元之間。與單詞邊界一樣,在文字的開頭也算作一個起始的行。結束行位置是在行的最後一個字元和換行符之間。與單詞邊界一樣,文字結束也算作行結束。 - 文字邊界
很多實現提供一個標記,通過改變它來改變^和$的含義。從“行開始”和“行結束”變成“文字開始”和“文字結束”。其它的一些實現提供單獨的元字元\A和\z來達到這個目的。
一些表示邊界的符號:
字元 含義 ^ 行的開頭 $ 行的結尾 \b 單詞邊界 \B 非單詞邊界 \A 輸入的開頭 \G 上一個匹配的結尾 \Z 輸入的結尾,僅用於最後的結束符(如果有的話) \z 輸入的結尾 其中^$是最常用的兩個邊界分隔符。
- 單詞邊界
捕獲和替換:
捕獲組
()在正則中被用來表示組,同時也可以用來捕獲匹配上的子串,可以擁有多個捕獲組,它們甚至可以巢狀使用,捕獲組從左到右進行編號,只要計算左圓括號。例如:
對於表示式:(\w+) had a ((\w+) \w+),文字是I had a nice day,那麼- 捕獲組1是I。
- 捕獲組2是nice day。
- 捕獲組3是nice。
- 捕獲組0是I had a nice day(根據具體實現不同)
如果表示式使用了兩個捕獲組,但是隻捕獲到一組,那麼組2是空字串。引用捕獲組使用+組序號,如\1表示引用第一個捕獲組。
- 後向引用
可以在同樣的表示式中引用同一個捕獲組,這稱為後向引用。
例:表示式[abc]{2}表示“匹配aa或ab或ac or ba或bb或bc或ca或cb或cc”,但是表示式([abc])\1表示“匹配aa或bb或cc”。
以上就是正則的全部知識,其實瞭解正則的知識點很簡單,但是真要應用到實際中還是需要通過大量的練習才能做到熟練使用。
實際案例
- 壓縮CSS檔案,去掉CSS檔案中的換行以及空格
工具:Notepad++ 查詢:([{;])\s+ 替換:\1
以上案例會不斷更新,已記錄一些自己對正則使用的經歷。