轉載請註明出處 來源:
paraller's blog原文排版鏈接:
點擊跳轉 html
想系統的學習正則表達式,在網上找了不少教程,其中《55分鐘學會正則表達式》這個翻譯自外網的教程講的最系統詳細,學完整個正則表達式的耗時大概在兩個多小時的樣子。
爲何寫這篇文章,由於我以爲若是不是這篇文章太生硬,廢話比較多,排版亂,有些地方存在錯誤的話,我以爲55分鐘就學完了。因此從新整理排版了一次。linux
學習的工具是 cat log | grep -E 'pattern'
git
.
.
表示匹配任何單個字符。下面這個正則表達式c.t
表明: 先找到c,接着找到任何單個字符,再找到t。c.t
的字符串,可是不包括ct或者coot。\
c\.t
,可以匹配文本 c.t
a\h
,能夠經過 a\\h
找到其中任意
的字符c[aeiou]t
表示「找到c後跟一個元音字母,再找到t」。將會匹配到cat[0123456789]
表示找到一個數字[a]
和a
意義相同:「找到a」一些轉義的例子:github
\[a\]
表示文本 [a]
[\[\]ab]
表示匹配一個 [
或者 ]
或者 a
或者 b
。[\\[\]]
表示「匹配一個\
或者 [
或者 ]
note:正則表達式
-
.
表示「匹配任意字符」,可是[.]
表示「匹配句點」你能夠在字符類中使用連字符來表示一個字母或數字的區間_:編程
[b-f]
和[bcdef]
一個意思[A-Z]
和[ABCDEFGHIJKLMNOPQRSTUVWXYZ]
都表示「匹配大寫字母」。[1-9]
和[123456789]
都表示「匹配一個非零數字」。區間和單獨的字符,可能會共存於同一個字符類:segmentfault
[0-9.,]
表示「匹配 一個數字 或者 一個.
或者 一個,
」。[0-9a-fA-F]
表示「匹配一個十六進制數」。[a-zA-Z0-9\-]
表示「匹配 一個字母數字字符 或 -
」。Note:編程語言
abc[!-/]
),但這在其它實現中的語法不必定對。即便語法正確,但在這個區間內很難看出包含了哪一個字符。請不要這麼幹[A-z]
這種表達式在你選擇的實現中合法,但它作的可能會與你想法用出入。[1-31]
表示 找到一個1或一個 2或一個3,不是找到一個從1到31的整數。你能夠經過在最開始的位置使^
來排除一個字符類。編輯器
[^a]
表示「匹配除了a的任意字符」。[^a-zA-Z0-9]
表示「找到一個非字母數字字符」。[\^abc]
表示「找到一個^
或者 a
或者 b
或者 c
」。[^\^]
表示「找到除了^
的任意字符」\d
含義與[0-9]
一致:「匹配一個數字」。\w
的含義與[0-9A-Za-z_]
一致:「匹配一個單詞字符,( 字母或數字或下劃線或漢字
)」。\s
表示「匹配任意空白字符(空格,tab)」。\s+
能夠表示回車和換行\D
同[^0-9]
:「匹配任意非數字的字符」。\W
同[^0-9A-Za-z_]
:「匹配任意非單詞字符(譯者注:匹配任意不是字母,數字,下劃線,漢字的字符)」。\S
表示「匹配任意不是空白符的字符」。\t
表示製表符[\u4e00-\u9fa5]
表示中文和英文[^\x00-\xff]
匹配雙字節字符,中文也是雙字節的字符,不包括英文能夠在字面值或者字符類後跟着一個大括號來使用乘法器。工具
a{1}
同a,表示「匹配一個a」。\d{3}
表示3個相連的數字。a{0}
表示「匹配空字符」。a\{2\}
表明文本 a{2}
。{
或者 }
。[abc]{2}
表示「匹配a
或者b
或者c
,接着匹配a
或者b
或者c
。這跟匹配aa
或bb
或cc
含義不一樣!x{4,4}
跟x{4}同樣。colou{0,1}r
表示「匹配colour或color。a{3,5}
表示「匹配aaaaa或aaaa或aaa」。a{1,}
表示「在一列中找到一個或多個a」。然而你的乘法器將會是貪婪的。在找到第一個a後,它將會盡量匹配到更多的a。.{0,}
表示「匹配任何情形」。無論你的輸入文本是什麼——甚至爲空注意:
I had an aaaaawful day
,該正則表達式就會在aaaaawful
中匹配到aaaaa
。不會在第三個a
後就中止匹配。I had an aaawful daaaaay
,以後這個正則表達式會在第一次的匹配中於aaawful
找到aaa。只有在你說「給我找到另外一個匹配」的時候,它纔會繼續搜索而後在daaaaay
中找到aaaaa?
表明的含義與{0,1}
相同。好比說,colou?r
表示「匹配colour或color」。*
等於{0,}
。好比說,*
表示「匹配一切」,跟上面提到的同樣。+
等於{1,}
。好比說,\w+
表示至少匹配一個或以上的單詞。 [0-9]+
表明至少匹配一個或以上數字\?\*\+
表示?*+
。[?*+]
表示找到一個?
或者一個*
或者一個+
。前面說到乘法器是貪婪的,能夠經過添加?
來消除貪婪特性
\d{4,5}?
就會等於 \d{4}
,在找到合適的文本以後就停下來".*?"
表示「匹配一個雙引號,跟着一個儘量少的字符,再跟着一個雙引號」。這實際上頗有用。你可使用管道符號來實現匹配多種選擇:
cat|dog
表示「匹配cat或dog」。red|blue|
和red||blue
以及|red|blue
都是一樣的意思,「匹配red或blue或空字符串」。a|b|c
跟[abc]
同樣。cat|dog|\|
表示「匹配cat或dog或管道符號」。[cat|dog]
表示「找到a或c或d或d或g或o或t或一個管道符號」。(Mon|Tues|Wednes|Thurs|Fri|Satur|Sun)day
。(\w*)ility
等同於\w*ility
。都表示「找到以ility結尾的單詞」。爲何第一種形式更有用,後面會看到...\(\)
表示「匹配一個(
後,再匹配一個)
」。[()]
表示「匹配一個(
或 一個)
」。單詞邊界是一個單詞字符和非單詞字符之間的位置。記住,一個單詞字符是w,它是[0-9A-Za-z_],一個非單詞字符是W,也就是1。
文本的開頭和結尾老是看成單詞邊界。輸入的文本it's a cat
有八個單詞邊界。若是咱們在cat
後追加一個空格,這裏就會有九個單詞邊界。
\
b表示「匹配一個單詞邊界」。\b\w\w\w\b
表示「匹配一個三個字母的單詞」。a\ba
表示「找到a,跟着一個單詞邊界,接着找到a」。無論輸入文本是什麼,這個正則表達式永遠都不會成功找到一個匹配。每一塊文本會分解成一個或多個行,用換行符分隔,像這樣:
^
表示「匹配開始行」。$
表示「匹配結束行」。^$
表示「匹配空行」。^.*$
將會匹配整個文本,由於換行符是一個字符,因此.會匹配它。爲了匹配單行,要使用惰性乘法器,^.?$
, ^.*?$
。\^\$
表示「匹配尖符號後跟着一個美圓符號」。[$]
表示「匹配一個美圓符」。然而,[^]
是非法單正則表達式。要記住的是尖符號在方括號中時有不一樣的特殊含義。把尖符號放在字符類中,這麼用[\^]
。這裏就是正則表達式開始變得異常強大的地方。
你已經知道,括號是用來表示組。它們也能夠用來捕獲子串。若是正則表達式是一個很小的電腦程序,這個捕獲組就是它的輸出(的一部分)。
正則表達式(\w*)ility
表示「找到一個以ility
結束的單詞」。捕獲組1就是匹配了部份內容的\w*
。
accessibility
,捕獲組1就是accessib
。ility
,捕獲組1就是空字符串。你能夠擁有多個捕獲組,它們甚至能夠嵌套使用。捕獲組從左到右進行編號。只要計算左圓括號。
假設咱們到正則表達式是(\w+) had a ((\w+) \w+)
。若是咱們的輸入文本是I had a nice day
,那麼:
捕獲組1是I
。
捕獲組2是nice day
。
捕獲組3是nice
。
在一些實現中,你可能能夠訪問捕獲組0,即完整匹配:I had a nice day
。
是的,這確實意味着圓括號有些重複。從一個成功返回的匹配中捕獲組數量老是等於原來正則表達式中捕獲組的數量。記住這一點,由於它能夠幫助你理解一些使人困惑的情形。
正則表達式((cat)|dog)
表示「匹配cat或dog」。這裏老是存在兩組捕獲組。若是咱們的輸入文本是dog,那麼捕獲組1是dog,捕獲組2是空字符串,由於另外一個選擇未被使用。
正則表達式a(\w)*
表示「 匹配一個以a開頭的單詞」。這裏老是隻有一個捕獲組(譯者注:除去捕獲組0):
a
,捕獲組1是空字符串。ad
,捕獲組1是d
。avocado
,捕獲組1是vocado
。一旦你用了正則表達式來查找字符串,你能夠指定另外一個字符串來替換它。第二個字符串時替換表達式。
你能夠在你的替換表達式中引用捕獲組。這是你能夠在替換表達式惟一能的特殊的事,它意味着你沒必要徹底銷燬你剛剛發現的東西。
比方說,你嘗試去用ISO 8691格式的日期(YYYY-MM-DD)去替換美式日期(MM/DD/YY)。
(\d\d)/(\d\d)/(\d\d)
開始。注意這裏有三個捕獲組:月,日和兩個數字表示的年。\
和一個捕獲組號來引用一個捕獲組。因此,你的替換表達式爲20\3-\1-\2
。若是咱們的輸入文本是03/04/05
(表示 3月4號,2005年),那麼:
03
;04
;05
;([\"])
中,捕獲組1是"
或者\
。\\\1
中,一個字面值反斜杆後跟着一個匹配的雙引號或者反斜杆。([abc])\1
表示匹配aa
或bb
或cc
。過分反斜線綜合徵(Excessive backslash syndrome)
在一些編程語言中,如Java,對於含有正則表達式的字符串沒有提供特別的支持。字符串有本身的轉義規則,這些規則與正則表達式的轉義規則疊加,一般會致使反斜杆過多(overload)。好比(仍是Java):
\d
在源代碼中變成String re = "\d;"
。"[^"]*"
變成String re = "\"[^\"]*\""
;。[\\\\[\\]]
變成String re = "[\\\\\\[\\]]"
;。String re = "\s"
;和String re = "[ ]"
;是同樣的。注意不一樣的轉義「優先級」。在其它編程語言裏,經過一個特殊標記來標識正則表達式,一般是正斜杆/。這裏有一些JavaScript例子:
\d
變成var regExp = /\d/
;。var regExp = /[\\\\[\\]]/
;。var regExp = /\s/
;和var regExp = /[ ]/
;同樣。var regExp = /https?:\/\//
;。基於這一點,我但願你明白爲何我對你反覆說起反斜杆。
題目以下:
"
的文本答案:
## Find: (_)([^\x00-\xff]+)+(_) ## Replace `\*\*\2\*\*`
[1-9]|[12][0-9]|3[01]
cat log | grep -E '"[^"]{0,}"'
cat log | grep -E '".{0,}"'
練習草稿
I had a nice day a,a a!b 90 "i love you , mary!" "i love you","hey" food z...z a b c d g e iec ieac c[abc]at 2016-10-22 12:12:12 cat c.t c\.t [a]
在文本編輯器中,會在你光標所在處開始搜索。這個編輯器會向前開始搜索文字,而後停在第一個匹配的地方。下一次搜索會在第一次完成搜索的地方的右側開始。
當編程的時候,文本的_偏移量_必須的。這個偏移量會在代碼中有明確的支持,或保存在包含文本的對象中(如Perl),或包含正則表達式的對象中(如JavaScirpt)。(在Java裏,這是一個由正則表達式和複合對象的字符串。)在任何狀況下,默認值> 0,表示文本的開始。搜索後,偏移量會自動更新,或者做爲輸出的一部分返回。
不管什麼狀況,一般很容易去使用循環來解決這個問題。
注意正則表達式匹配空字符串是徹底可能的。 你能夠立馬實現的一個簡單的例子是a{0}在這種狀況下,新的偏移量等於舊偏移量,從而致使死循環。
一些實現可能保護你避免發生這些狀況,但要查下對應的文檔。
動態地構造一個正則表達式字符串時必定要當心。若是你使用的字符串不是固定的,那麼它可能包含意想不到的元字符。這會致使語法錯誤。更糟糕的是,它可能產生一個語法正確,但行爲不可預期的正則表達式。
有bug的Java代碼:
String sep = System.getProperty("file.separator"); String[] directories = filePath.split(sep);
這個bug就是:String.split()
認爲sep是一個正則表達式。可是在Windows下,sep是由犯斜杆組成的字符串\
.這不是一個語法正確的正則表達式。結果是:一個異常PatternSyntaxException。
任何一個優秀的編程語言都提供了一種機制,用以轉義在一個字符串中出現的全部元字符。在Java中,你能夠這麼作:
String sep = System.getProperty("file.separator"); String[] directories = filePath.split(Pattern.quote(sep));
不要使用正則表達式來驗證郵件地址。
首先,這很難保證正確無誤。電子郵件地址確實符合一個正則表達式,可是這個表達式長又複雜地讓人聯想到世界末日。任何縮略都會可能產生遺漏(false negatives)。(你知道嗎?電子郵件地址能夠包含註釋!)
其次,即便所提供的電子郵件地址符合正則表達式,但也並不能證實它的存在。驗證電子郵件地址的惟一方法是發送電子郵件給它。
在正式的應用中,不要使用正則表達式來解析HTML或XML。解析HTML/XML是
不可能使用簡單的正則
通常來講很難
一個已解決了的問題。
不妨找一個已有的解析庫來爲你搞定這些工做。
Host segmentfault.com Connection keep-alive Content-Length 55 Accept */* Origin https://segmentfault.com X-Requested-With XMLHttpRequest User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
^(\S+)(\s+)(.{0,}) "\1":"\3",
"Host":"segmentfault.com", "Connection":"keep-alive", "Content-Length":"55", "Accept":"*/*", "Origin":"https://segmentfault.com", "X-Requested-With":"XMLHttpRequest", "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
--- layout: post tags: - linux --- ---(\n(.{0,}))*---