正則(轉)

正則對於新人來講是一個頭疼的名字,讓人聞而生畏。可是,在我看來,正則,並無那麼神祕,但願能經過這篇正則表達式入門教程解除正則新人對於正則的畏懼感。javascript

接觸正則應該有三年不止了吧,我也不知道本身怎麼就走過了畏懼正則的時期,並且在一個小圈子裏面還成了正則強人。php

今天就基於我對正則的理解,簡單描述一下我眼裏的正則,但願這篇正則表達式入門教程可以解除正則新人對於正則的畏懼感。html

 

 

先歸納一下,正則三段論:java

 

定錨點,去噪點,取數據

 

1、入門:正則字符

關於正則字符,不少文章都會講到,足足有一篇文章才能描述清楚,我這裏就很少說,對於我,平時,經常使用的有:正則表達式

 

1. . 匹配不包括換行的任意字符

在php的s修飾符(單行模式)下面能夠匹配換行,如$pattern='#<div>(.*?)</div>#s';就能夠匹配div內容有換行的數據。vim

若是須要匹配包括換行的任意字符,可使用[\s\S]代替.數組

 

2. \s 空格、tab、換行

[\s\S]表示匹配任意字符,\S是\s的反義。
注意區分[\s\S]與.的區別。
 

3. * 匹配零個或更多個,即0~n

 

4. + 匹配一個或更多個,即至少一個,1~n

 

5. \ 轉義

一個特殊字符前加\就表示轉義,說明把它當普通字符用ide

 

6. [] 單字符取一個,好比[abc]會匹配a或b或c

可是,若是[]裏面加上^則會變成排除這個字符,如[^abc]就表示不是a、不是b、也不是c 
另外,在[]裏面可使用-表示一個範圍,如[0-9]表示從0到9,相似的還有[a-zA-Z],若是要包含-字符,能夠給它加上轉義[\-]。 
關於[]常見的錯誤用法是:[ab|bc]用來表示abbc,實際上,它獲得的結果是[abc|],即a或b或c或|這4個字符(單字符)的任意一個。這裏能夠改爲(ab|bc)。 
總結:[]裏面的特殊符有五個:[]-\^,其餘字符都是普通字符,包括*.?等。 
說明: 
^[^ 的首位時候纔有特殊意義 
[0-9 -在不是首尾的時候有特殊意義 
\[ \] 由於佔用[] 自己字符,因此有特殊意義 
\自己是轉義符,有特殊意義svn

 

7. ^ 字符串開始

這裏的^跟[]裏面用的^是同一個字符,可是卻不是一個意思,這裏它表示整個字符串的開始,好比^www表示以www開頭的字符串,注意區分,不在[]裏面的是開始符,在裏面的排除學習

 

8. $ 字符串結束

 

9. {1,3} 循環次數

[0-9]{1,3}表示在0-9的範圍裏面循環1個、2個或者3個,可能結果有五、20、415等。 
若是循環指定次數,如3次,則{3,3}能夠簡寫成{3}。 
若是恰好須要匹配字符{1},則正則須要給{進行轉義,獲得\{1}的正則。 
若是{}中間不是數字,則{}自己不須要轉義。

 

10. ? 有兩個用法

 

(1) 匹配一個或零個

好比https?匹配的https(一個s)或者http(零個s)

 

(2)非貪婪模式

所謂非貪婪模式,就是匹配儘量少的內容,好比,對於源字符串

 
  1. <div>a</div><div>b</div>

使用<div>(.*?)</div>會獲得2個結果(注意:若是源字符串有換行,使用[\s\S]替換 . ):

 
  1. <div>a</div>

 
  1. <div>b</div>

由於,當遇到第一個</div>,非貪婪模式就不會再日後找了。 
而使用<div>(.*)</div>(貪婪模式)則會獲得整個字符串

 
  1. <div>a</div><div>b</div>

,由於它會匹配全部字符直到後面再找不到</div>

更多關於?的使用,能夠參考《正則表達式匹配次數

 

11. | 多個數據選一(經常使用於多字符)

前面提到[]裏面的字符有選一個字符功能,可是假如不是一個字符,好比:http|ftp|svn 就須要用|分開,|的做用域是一直日後直到遇到括號,好比,對於源字符串

 
  1. http abc
  2. ftp abc
  3. svn abc

http|ftp|svn abc匹配的結果是:

 
  1. http

 
  1. ftp

 
  1. svn abc

想要匹配 http abcftp abcsvn abc就要使用括號把前邊的協議括起來,如(http|ftp|svn) abc 能夠獲得預期的結果。

 

12. () 數據分界和取數據

上面例子(http|ftp|svn) abc就是數據分界的例子,而後,匹配結果會獲得一個[1]的子集數據(數組下標1),這裏就是子模式的概念,子模式也叫分組,利用子模式,能夠獲得想要取出來的數據。子模式一、二、3的計算方法爲左括號的計數,從左到右,從1開始,好比: 
(http|ftp|svn)://([^/]+),分組1獲得的是(http|ftp|svn)裏面的數據,分組2獲得([^/]+)裏面的數據,對於嵌套括號也是點左括號便可。在正則中有不少與括號結合的寫法,你在數左括號的時候,必定要注意,非捕獲組和環視的左括號都是不須要數的。 
在使用子模式過程當中,常見兩種寫法是:\1 和 $1。 
(1) \1 是在正則表達式自己中引用分組1的內容,如: 
咱們要匹配111這樣的連續出現3此的數字,咱們能夠寫出正則:(\d)\1\1(\d)匹配到第一個1,後面再引用這個匹配內容,獲得111。 
(2) $1 是在替換中調用分組的內容,如: 
咱們要替換連接參數name=Zjmainstayusername=Zjmainstay,咱們可使用正則name=([^&]+)替換爲username=$1來實現,這裏的$1就引用了分組1的結果Zjmainstay,所以獲得咱們想要的結果。

 

13. (?:) 非捕獲組

上面說到()做爲子模式能夠獲得它裏面的數據,可是,有些時候,()只是做爲數據分界功能,並不須要取出來,這時候就要用到非捕獲組的概念了。好比:(http|ftp|svn)://([^/]+)只想獲得域名,也就是[2],那麼(http|ftp|svn)就只是數據分界的功能,這裏不須要捕獲,所以使用非捕獲組功能,(?:http|ftp|svn)屏蔽這部分的數據獲取,此時,(?:這個左括號排除[1]計數,也就是(?:http|ftp|svn)://([^/]+)中的([^/]+)變成[1]了。

 

14. 分隔符

在一些語言中,你會發現正則第一個和最後一個字符是相同的,如: 
/\d+/ 
這個/ /在PHP中稱爲分隔符,正則表達式須要由分隔符閉合包裹。在PHP中,分隔符可使任意非字母數字、非反斜線、非空白字符。這個概念很關鍵,它能幫助咱們簡化一些正則的書寫,避免錯誤,如: 
/<div>.*?</div>/ 
這個正則是錯誤的。 
緣由是</div>/與分隔符相同,可是卻沒有作轉義。 
以下程序:

 
  1. preg_match('/<div>.*?</div>/', '<div>abc</div>', $match);

PHP中會收到錯誤提示:Warning: preg_match(): Unknown modifier 'd' in regexTest.php on line 2 
對於這種狀況,有兩種解決方案: 
(1)/<div>.*?<\/div>/ 
(2)#<div>.*?</div># 
方案(1)是對正則內部的分隔符作轉義,方案(2)是規避了原本的/分隔符,使用#做爲分隔符,從而避免/須要轉義。 
雖然不少狀況下,都是看到先後一致的分隔符,可是,你們須要瞭解一下,[<div>.*?</div>]這個表達式在PHP裏也是合法的。(不提倡使用,僅瞭解!)

 

15. 模式修飾符

模式修飾符在許多程序語言中都支持的,好比最多見的是i,不區分大小寫,如javascript裏的/[a-z0-9]/i,表示匹配字母數字,不區分大小寫。

本人在寫php正則時經常使用的模式修飾符主要有is,如: 
$pattern = '#[a-z0-9]+#is';

模式修飾符s的做用主要是的.可以匹配換行,在處理換行數據時,一般會用到。

在PHP中,模式修飾符有兩種用法,一種是上面的,在分隔符後面的模式修飾符,它的做用範圍是全局;另外一種是在正則表達式中間的。 
例如:

 
  1. 正則:/((?i)[A-Z]+)c/
  2. 測試字符:abcABC
  3. 匹配:abc
  4. 說明:局部(ab)的大小寫被忽略了,(?i)的做用範圍在分組1

若是把正則改爲:/([A-Z]+)c/i,則匹配結果將是:abcABC 
示例地址:PHP正則表達式中間的模式修飾符 (選擇Version 1/2切換版本查看結果區別)

關於PHP模式修飾符的講解,請查看PHP手冊中的《PHP模式修飾符》。


關於經常使用字符的使用差很少到這裏,還有更多的請參考正則表達式30分鐘入門教程,這是我看過比較全面的正則入門資料。

 

2、 操做:定錨點

注:這裏的錨點區分於正則本來關於錨點的定義,此處是肯定的參照文本的意思,如a標籤裏的<a

每個正則都是有針對性的,只有這樣正則纔有意義。所以,寫正則以前,先觀察你要解析的數據,找準惟一的錨點,好比,你要解析一個頁面的title標籤,獲得title內容,那麼這個title就是錨點。有時候,所要取的數據確實沒法定位一個惟一的錨點,那麼,你能夠分解數據,先經過一個惟一錨點鎖定你的數據塊,取出來以後,再對這個數據塊取數據便可。好比,有這麼一段源字符串:

 
  1. <div id="module_1">
  2. <div class="content">
  3. content 1
  4. </div>
  5. </div>
  6. <div id="module_2">
  7. <div class="content">
  8. content 2
  9. </div>
  10. </div>

你直接經過class="content"來匹配數據的話很明顯會獲得兩個,那麼,你能夠擴展它的數據域,先以id="module_1"做爲錨點,獲取整個

 
  1. <div id="module_1">
  2. <div class="content">
  3. content 1
  4. </div>
  5. </div>

而後在對這個數據塊的數據處理,獲得class="contents"的內容便可。 
所以,這裏用到2個正則:

(1)<div id="module_1">(.*?)</div>\s*<div id="module_2"> 
(2)<div class="content">(.*?)</div>

固然,這個正則能夠改進爲: 
<div id="module_1">\s*<div class="content">(.*?)</div>

注:爲了更清晰查看,前面源碼作了換行,匹配失敗的朋友,能夠修改 .*? 爲 [\s\S]*? 修正正則。

 

總結:錨點,就是能惟必定位你數據的標識

 

3、 操做:去噪點

所謂去噪點,就是把無關的東西都當浮雲,用通配符過掉它,只關心咱們想要的數據,好比: 
<meta content="text/html; charset=utf-8" http-equiv="content-type"> 
要從這裏獲得字符集utf-8,咱們須要怎麼作? 
首先,定位錨點,有<meta 、charset=和utf-8後面的",其餘都是浮雲~ 
所以獲得正則: 
<meta[^>]*?charset=([^"]+)" 
便可,用子模式取數據[1]就能獲得utf-8

 

總結:關心的留下,不關心的都是浮雲

 

4、 操做:取數據

關於取數據,上面一大篇下來你們應該有概念了,就是利用子模式來獲取,這裏再也不贅述。

 

總結:子模式計數,數左括號從1開始,排除非捕獲組的左括號

 

5、正則表達式高級教程

關於正則表達式的高級教程,請閱讀《深刻正則表達式應用 - 正則表達式高級教程

 

最後,但願你們有一個愉悅的正則之旅,你必定會愛上她的,跟我同樣。: )

轉載請附帶本文原文地址: 我眼裏的正則表達式入門教程,首發自  Zjmainstay學習筆記
相關文章
相關標籤/搜索