講的不錯,感謝做者,轉自:http://blog.jobbole.com/63398/ 程序員
正則表達式是一種查找以及字符串替換操做。正則表達式在文本編輯器中普遍使用,好比正則表達式被用於:正則表達式
與文本編輯器類似,幾乎全部的高級編程語言都支持正則表達式。在這樣的語境下,「文本」也就是一個字符串,能夠執行的操做都是相似的。一些編程語言(好比Perl,JavaScript)會檢查正則表達式的語法。編程
正則表達式是什麼?編程語言
正則表達式只是一個字符串。沒有長度限制,可是,這樣的正則表達式長度每每較短。以下所示是一些正則表達式的例子:編輯器
I had a \S+ day today
[A-Za-z0-9\-_]{3,16}
\d\d\d\d-\d\d-\d\d
v(\d+)(\.\d+)*
TotalMessages="(.*?)"
<[^<>]>
在實現中,正則表達式還有其餘的特色。本文將重點討論正則表達式的核心語法,在幾乎全部的正則表達式中均可以見到這些規則。函數
特別提示:正則表達式與文件通配語法無關,好比 *.xml網站
正則表達式中包含了一系列的字符,這些字符只能匹配它們自己。有一些被稱爲「元字符」的特殊字符,能夠匹配一些特殊規則。ui
以下所示的例子中,我用紅色標出了元字符。this
I had a \S+ day today
[A-Za-z0-9\-_]{3,16}
\d\d\d\d-\d\d-\d\d
v(\d+)(\.\d+)*
TotalMessages="(.*?)"
<[^<>]*>
大部分的字符,包括全部的字母和數字字符,是普通字符。也就意味着,它們只能匹配它們本身,以下所示的正則表達式:spa
cat
意味着,只能匹配一個字符串,以「c」開頭,而後是字符「a」,緊跟着是字符「t」的字符串。
到目前爲止,正則表達式的功能相似於
String.indexOf()
函數strpos()
函數咱們第一個要講解的元字符是「.」。這個符號意味着能夠匹配任意一個字符。以下所示的正則表達式:
c.t
意味着匹配「以c開頭,以後是任意一個字符,緊跟着是字母t」的字符串。
在一段文本中,這樣的正則表達式能夠用來找出cat
, cot
, czt這樣的字符串,甚至能夠找出c.t這樣的組合,可是不能找到ct或者是coot這樣的字符串。
使用反斜槓「\」能夠忽略元字符,使得元字符的功能與普通字符同樣。因此,正則表達式
c\.t
表示「找到字母c,而後是一個句號(「.」),緊跟着字母t」
反斜槓自己也是一個元字符,這意味着反斜槓自己也能夠經過類似的方法變回到普通字符的用途。所以,正則表達式
c\\t
表示匹配「以字符c開頭,而後是一個反斜槓,緊跟着是字母t」的字符串。
注意!在正則表達式的實現中,.是不能用於匹配換行符的。」換行符「的表示方法在不一樣實現中也不一樣。實際編程時,請參考相關文檔。在本文中,我認爲.是能夠匹配任意字符的。實現環境一般會提供一個Flag標誌位,來控制這一點。
字符類是一組在方括號內的字符,表示能夠匹配其中的任何一個字符。
包含忽略字符的例子
表示匹配字符串[a]
\[\]
\ab]表示匹配的字符爲」["或者'']」或者」a」,或者」b」\[\]
]表示匹配的字符爲」\」或者 「[」或者"]「在字符類中,字符的重複和出現順序並不重要。[dabaaabcc]與[abc]是相同的
重要提示:字符類中和字符類外的規則有時不一樣,一些字符在字符類中是元字符,在字符類外是普通字符。一些字符正好相反。還有一些字符在字符類中和字符類外都是元字符,這要視狀況而定!
好比,.表示匹配任意一個字符,而[.]表示匹配一個全角句號。這不是一回事!
在字符集中,你能夠經過使用短橫線來表示匹配字母或數字的範圍。
使用目前咱們已經講解的正則表達式相關知識,在字典中匹配找到含有最多連續元音的單詞,同時找到含有最多連續輔音的單詞。
[aeiou][aeiou][aeiou][aeiou][aeiou][aeiou]
這樣的正則表達式,能夠匹配連續含有六個元音的單詞,好比 euouae
和 euouaes
。
一樣的,恐怖的正則表達式
[bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz]
能夠找到連續含有十個輔音的單詞sulphhydryls
.
下文中,咱們會講解,怎樣有效縮短這樣的正則表達式長度。
在字符類以外,短橫線沒有特殊含義。正則表達式a-z,表示匹配字符串「以a開頭,而後是一個短橫線,以z結尾」。
範圍和單獨的字符可能在一個字符類中同時出現:
使用已經介紹過的正則表達式知識,匹配YYYY-MM-DD格式的日期。
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
.
一樣的,下文中,咱們會介紹怎樣有效減小這樣的正則表達式長度。
雖然你能夠嘗試在正則表達式中使用一些非字母或數字做爲範圍的最後一個符號,好比abc[!-/]def,可是這並非在每種實現中都合法。即便這樣的語法是合法的,這樣的語義也是模糊的。最好不要這樣使用。
同時,你必須謹慎選擇範圍的邊界值。即便[A-z]在你使用的實現中,是合法的,也可能會產生沒法預料的運行結果。(注意,在z到a之間,是有字符存在的)
注意:範圍的字符值表明的是字符而已,並不能表明數值範圍,好比[1-31]表示匹配一個數字,是1或者2或者3,而不是匹配一個數值在1到31之間的數。
你能夠在字符類的起始位放一個反義符。
在字典中,找到一個不知足「在e以前有i,可是沒有c」的例子。
cie和[^c]ei都要能夠找到不少這樣的例子,好比ancient,science,viel,weigh
\d這個正則表達式與[0-9]做用相同,都是匹配任何一個數字。(要匹配\d,應該使用正則表達式\\d)
\w與[0-9A-Za-z]相同,都表示匹配一個數字或字母字符
\s意味着匹配一個空字符(空格,製表符,回車或者換行)
另外
這些是你必須掌握的字符。你可能已經注意到了,一個全角句號「.」也是一個字符類,能夠匹配任意一個字符。
不少正則表達式的實現中,提供了更多的字符類,或者是標誌位在ASCII碼的基礎上,擴展示有的字符類。
特別提示:統一字符集中包含除了0至9以外的更多數字字符,一樣的,也包含更多的空字符和字母字符。實際使用正則表達式時,請仔細查看相關文檔。
簡化正則表達式 [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
.
\d\d\d\d-\d\d-\d\d
.
在字符或字符集以後,你可使用{ }大括號來表示重複
簡化下面的正則表達式
z.......z
\d\d\d\d-\d\d-\d\d
[aeiou][aeiou][aeiou][aeiou][aeiou][aeiou]
[bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz]
z.{7}z
\d{4}-\d{2}-\d{2}
[aeiou]{6}
[bcdfghjklmnpqrstvwxyz]{10}
注意:重複字符是沒有記憶性的,好比[abc]{2}表示先匹配」a或者b或者c」,再匹配」a或者b或者c」,與匹配」aa或者ab或者ac或者ba或者bb或者bc或者ca或者cb或者cc「同樣。[abc]{2}並不能表示匹配」aa或者bb或者cc「
重複次數是能夠指定範圍的
注意這樣的正則表達式會優先匹配最長字符串,好比輸入 I had an aaaaawful day
會匹配單詞aaaaawful中的aaaaa,而不會匹配其中的aaa。
重複次數是能夠有範圍的,可是有時候這樣的方法也不能找到最佳答案。若是你的輸入文本是I had an aaawful daaaaay那麼在第一次匹配時,只能找到aaawful,只有再次執行匹配時才能找到daaaaay中的aaaaa.
重複次數的範圍能夠是開區間
使用正則表達式找到雙引號。要求輸入字符串可能包含任意個字符。
調整你的正則表達式使得在一對雙引號中間再也不包含其餘的雙引號。
".{0,}"
, 而後 "[^"]{0,}"
.
?與{0,1}相同,好比,colou?r表示匹配colour或者color
*與{0,}相同。好比,.*表示匹配任意內容
+與{1,}相同。好比,\w+表示匹配一個詞。其中」一個詞」表示由一個或一個以上的字符組成的字符串,好比_var或者AccountName1.
這些是你必須知道的經常使用轉義字符,除此以外還有:
簡化下列的正則表達式:
".{0,}"
and "[^"]{0,}"
x?x?x?
y*y*
z+z+z+z+
".*"
and "[^"]*"
x{0,3}
y*
z{4,
}寫出正則表達式,尋找由非字母字符分隔的兩個單詞。若是是三個呢?六個呢?
\w+\W+\w+
, \w+\W+\w+\W+\w+
, \w+\W+\w+\W+\w+\W+\w+\W+\w+\W+\w+
.
下文中,咱們將簡化這個正則表達式。
正則表達式 「.*」 表示匹配雙引號,以後是任意內容,以後再匹配一個雙引號。注意,其中匹配任意內容也能夠是雙引號。一般狀況下,這並非頗有用。經過在句尾加上一個問號,可使得字符串重複再也不匹配最長字符。
你可使用|來分隔能夠匹配的不一樣選擇:
簡化下列正則表達式:
s|t|u|v|w
aa|ab|ba|bb
[abc]|[^abc]
[^ab]|[^bc]
[ab][ab][ab]?[ab]?
答案
[s-w]
[ab]{2}
.
[^b]
[ab]{2,4}
使用正則表達式匹配1到31之間的整數,[1-31]不是正確答案!
這樣的正則表達式不惟一. [1-9]|[12][0-9]|3[01]
是其中之一。
你可使用括號表示分組:
在《時間機器中》找到一對括號中的內容,而後經過修改正則表達式,找到不含括號的內容。
.∗
. 而後是, [()]∗
.
分組能夠包括空字符串:
你也能夠在分組的基礎上使用重複:
簡化正則表達式 \w+\W+\w+\W+\w+
以及 \w+\W+\w+\W+\w+\W+\w+\W+\w+\W+\w+
.
\w+(\W+\w+){2}
, \w+(\W+\w+){5}
.
在單詞和非單詞之間有單詞分隔符。記住,一個單詞\w是[0-9A-Za-z_],而非單詞字符是\W(大寫),表示[^0-9A-Za-z_].
在文本的開頭和結尾一般也有單詞分隔符。
在輸入文本it’s a cat中,實際有八個單詞分隔符。若是咱們在cat以後在上一個空格,那就有九個單詞分隔符。.
單詞分隔符自己並非字符。它們的寬度爲0。下列正則表達式的做用不一樣
(\bcat)\b
(\bcat\b)
\b(cat)\b
\b(cat\b)
在詞典中找到最長的單詞。
在嘗試以後發現,\b.{45,}\b能夠在字典中找到最長單詞
一篇文本中能夠有一行或多行,行與行之間由換行符分隔,好比:
注意,全部的文本都是以一行結束的,而不是以換行符結束。可是,任意一行均可能爲空,包括最後一行。
行的起始位置,是在換行符和下一行首字符之間的空間。考慮到單詞分隔符,文本的起始位置也能夠當作是首行位置。
最後一行是最後一行的尾字符和換行符之間的空間。考慮到單詞分隔符,文本的結束也能夠認爲是行的結束。
那麼新的格式表示以下:
基於上述概念:
^.*&
表示匹配全文內容,由於行的開始符號也是一個字符,"."會匹配這個符號。找到單獨的一行,可使用
^.*?$與字符分隔符同樣,換行符也不是字符。它們寬度爲0.以下所示的正則表達式做用不一樣:
(^cat)$
(^cat$)
^(cat)$
^(cat$)
使用正則表達式在《時間機器》中找到最長的一行。
使用正則表達式^.{73,}$能夠匹配長度爲73的一行
在不少的正則表達式實現中,將^和$做爲文本的開始符號和結束符號。
還有一些實現中,用\A和\z做爲文本的開始和結束符號。
從這裏開始,正則表達式真正體現出了它的強大。
你已經知道了使用括號能夠匹配一組符號。使用括號也能夠捕獲子串。假設正則表達式是一個小型計算機程序,那麼捕獲子串就是它輸出的一部分。
正則表達式(\w*)ility表示匹配以ility結尾的詞。第一個被捕獲的部分是由\w*控制的。好比,輸入的文本內容中有單詞accessibility,那麼首先被捕獲的部分是accessib。若是輸入的文本中有單獨的ility,則首先被捕獲的是一個空字符串。
你可能會有不少的捕獲字符串,它們可能靠得很近。捕獲組從左向右編號。也就是隻須要對左括號計數。
假設有這樣的正則表達式:(\w+) had a ((\w+) \w+)
輸入的內容是:I had a nice day
在一些正則表達式的實現中,你能夠從零開始編號,編號零表示匹配整句話:I had a nice day
.
在其餘的實現中,若是沒有制定捕獲組,那麼捕獲組1會自動地填入捕獲組0的信息。
是的,這也意味着會有不少的括號。有一些正則表達式的實現中,提供了「非捕獲組」的語法,可是這樣的語法並非標準語法,所以咱們不會介紹。
從一個成功的匹配中返回的捕獲組個數,與使用原來的正則表達式得到的捕獲組個數相同。記住這一點,你能夠解釋一些奇怪的現象。.
正則表達式((cat)|dog)表示匹配cat或者dog。這裏有兩個捕獲組,若是輸入文本是dog,那麼捕獲組1是dog,捕獲組2爲空。
正則表達式a(\w)*表示匹配一個以a開頭的單詞。這裏只有一個捕獲組
假如你使用了一個正則表達式去匹配字符串,你能夠描述另一個字符串來替換其中的匹配字符。用來替換的字符串稱爲替換表達式。它的功能相似於
將《時間機器》中全部的元音字母替換爲r。
使用正則表達式[aeiou]以及[AEIOU],對應的替換字符串分別爲r,R.
可是,你能夠在替換表達式中引用捕獲組。這是在替換表達式中,你能夠惟一操做的地方。這也是很是有效的,由於這樣你就不用重構你找到的字符串。
假設你正在嘗試將美國風格的日期表示MM/DD/YY替換爲ISO 8601日期表示YYYY-MM-DD
20\3-\1-\2
.2005-03-04
.在替換表達式中,你能夠屢次使用捕獲組
在某些實現中,採用美圓符號$代替\
使用正則表達式和替換表達式,將23h59這樣的時間戳轉化爲23:59.
正則表達式finds the timestamps, 替換表達式\1:\2
在一個正則表達式中,你也能夠引用捕獲組。這稱做:反向引用
好比,[abc]{2}表示匹配aa或者ab或者ac或者ba或者bb或者bc或者ca或者cb或者cc.可是{[abc]}\1表示只匹配aa或者bb或者cc.
在字典中,找到包含兩次重複子串的最長單詞,好比papa
, coco
\b(.{6,})\1\b
匹配 chiquichiqui
.
若是咱們不在意單詞的完整性,咱們能夠忽略單詞的分解,使用正則表達式 (.{7,})\1
匹配
countercountermeasure
以及 countercountermeasures
.
特別提醒:
在一些編程語言,好比Java中,對於包含正則表達式的字符串沒有特殊標記。字符串有着本身的過濾規則,這是優先於正則表達式規則的,這是頻繁使用反斜槓的緣由。
好比在Java中
"[^"]*"
變爲String re = 「\」[^\"]*\」"\[\]
] 變爲String re = 「[\\\\\
]」;
String re = "\\s";
和String re = "[ \t\r\n]";
是等價的. 注意它們實際執行調用時的層次不一樣。在其餘的編程語言中,正則表達式是由特殊標明的,好比使用/。下面是JavaScript的例子:
var regExp = /\d/;
.var regExp = /[\\\[\]
]/;
var regExp = /\s/;
和 var regExp = /[ \t\r\n]/;
是等價的var regExp = /https?:\/\//;
.我但願如今你能明白,我爲何讓你特別注意反斜槓。
當你動態建立一個正則表達式的時候請特別當心。若是你使用的字符串不夠完善的花,可能會有意想不到的匹配結果。這可能致使語法錯誤,更糟糕的是,你的正則表達式語法正確,可是結果沒法預料。
錯誤的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));
將正則表達式字符串加入反覆運行的程序中,是一種開銷很大的操做。若是你能夠在循環中避免使用正則表達式,你能夠大大提升效率。
在一個網站上,我輸入了個人卡號好比 1234 5678 8765 4321
網站拒絕接收。由於它使用了正則表達式\d{16}。
正則表達式應該考慮到用戶輸入的空格和短橫線。
實際上,爲何不先過濾掉全部的非數字字符,而後再進行有效性驗證呢?這樣作,能夠先使用\D以及空的替換表達式。
在不先過濾掉全部的非數字字符的狀況下,使用正則表達式驗證卡號的正確性。
\D*(\d\D*){16}
is one of several variations which would accomplish this.
不要使用正則表達式來驗證姓名。實際上,即便能夠,也不要企圖驗證姓名。
程序員對名字的錯誤見解:
不要使用正則表達式驗證郵箱地址的正確性。
首先,這樣的驗證很難是精確的。電子郵件地址是能夠用正則表達式驗證的,可是表達式會很是的長而且複雜。
短的正則表達式會致使錯誤。(你知道嗎?電子郵箱地址中會有一些註釋)
第二,即便一個電子郵件地址能夠成功匹配正則表達式,也不表明這個郵箱實際存在。郵箱的惟一驗證方法,是發送驗證郵件。
在嚴格的應用場景中,不要使用正則表達式來解析HTML或者XML。解析HTML或者XML:
找到一個已經有的解析庫來完成這個工做
總結:
a
b
c
d
1
2
3
4
etc..
[abc]
[a-z]
\d
\w
\s
.
表明任何字符\d
表示
「數字」\w
表示」字母」, [0-9A-Za-z_]
\s
表示 「空格, 製表符,回車或換行符」[^abc]
\D
\W
\S
{4}
{3,16}
{1,}
?
*
+
?
表示 「零次或一次」*
表示 「大於零次」+
表示 「一次或一次以上」(Septem|Octo|Novem|Decem)ber
\b
^
$
\A
\z
\1
\2
\3
etc. (在匹配表達式和替換表達式中均可用).
\
[
]
{
}
?
*
+
|
(
)
^
$
[
]
\
-
^
\
正則表達式很是經常使用並且很是有用。每一個人在編輯文本或是編寫程序時都必須瞭解怎樣使用正則表達式。