快速掌握正則表達式

關鍵詞 正則 狀態機 環視匹配 等價轉換 限定符 內聯模式java

一.DFA引擎 or NFA引擎

不一樣類型的正則引擎對一樣的正則表達式執行的結果是不一樣的。搞清楚引擎是必要的。git

概念

DFA(Deterministic Finite Automaton)爲肯定性有限自動機,NFA(Non-deterministic Finite Automaton)爲非肯定性有限自動機。正則表達式

  • DFA 引擎在線性時狀態下執行,由於它們不要求回溯(並所以它們永遠不測試相同的字符兩次)
  • NFA包含回溯算法也叫試探法,從一條路往前走,能進則進,不能進則退回來,換一條路再試。回溯算法說白了就是窮舉法。所以,在最壞狀況下,它的執行速度可能很是慢。

能夠用以下的正則表達式測試當前編程語言採用的引擎是否 NFA:nfa|nfa not算法

js:"nfa,nfa not".match(/nfa|nfa not/)  結果 ["nfa", index: 0, input: "nfa,nfa not", groups: undefined]
js:/nfa|nfa not/.test('nfa')  結果 true 
複製代碼

用上面的正則表達式來測試字符串 nfa not,NFA 引擎在檢測知足 nfa 就返回匹配成功的結果了,而 DFA 則會嘗試繼續查找,也就是說會獲得「最長的匹配結果」。編程

知識點:自動機、自動機bash

如/\d\w+/這個正則生成的狀態機圖:網絡

關於正則引擎如何工做這裏有一個不錯的說明,先說明了DFA工做的方法,而後又引出了「回溯」less

正則引擎語言分類

DFA類型 語言
DFA awk (大多數版本)、egrep(大多數版本)、flex、lex、MySQL、Procmail
傳統型NFA GNU Emacs、Java、grep(大多數版本)、less、more、.NET語言、PCRE library、Perl、PHP(全部三套正則庫)、Python、Ruby、sed(大多數版本)、vi ,JavaScript
POSIX NFA mawk、Mortice Kern Systems’ utilities、GNU Emacs (明確指定時使用)
DFA/NFA 混合 GNU awk、GNU grep/egrep、Tcl

不一樣的語言對於正則表達式符號的支持狀況也是不一樣的。 編程語言

二.正則表達式

經常使用符號

簡潔版post

  • ?表示匹配0個或1個
  • +表示匹配1-無窮
  • *表示匹配0-無窮
  • .表示除\n以外的任意字符
  • ^爲匹配輸入字符串的開始位置
  • $匹配結束位置
  • \d就是[0-9]。表示是一位數字。記憶方式:其英文是digit(數字)。
  • \D就是[^0-9]。表示除數字外的任意字符。
  • \w就是[0-9a-zA-Z_]。表示數字、大小寫字母和下劃線。記憶方式:w是word的簡寫,也稱單詞字符。
  • \W是[^0-9a-zA-Z_]。非單詞字符。
  • \s是[ \t\v\n\r\f]。表示空白符,包括空格、水平製表符、垂直製表符、換行符、回車符、換頁符。記憶方式:s是space character的首字母。
  • \S是[^ \t\v\n\r\f]。 非空白符。.就是[^\n\r\u2028\u2029]。通配符,表示幾乎任意字符。換行符、回車符、行分隔符和段分隔符除外。記憶方式:想一想省略號...中的每一個點,均可以理解成佔位符,表示任何相似的東西。

wsb 和 WSB 是相反的

等價 \w = [A-Za-z0-9_], 展開看好理解

分解: 沒法一步就完成的需求能夠分解,如獲取網頁中的圖片地址, 先獲取img標籤,而後再從標籤中獲取src值

特殊字符

參考版

特別字符 描述
$ 匹配輸入字符串的結尾位置。若是設置了 RegExp 對象的 Multiline 屬性,則$ 也匹配 '\\n' 或 '\\r'。要匹配 $ 字符自己,請使用 \\$
( ) 標記一個子表達式的開始和結束位置。子表達式能夠獲取供之後使用。要匹配這些字符,請使用 \( 和 \)。
* 匹配前面的子表達式零次或屢次。要匹配 * 字符,請使用 \*。
+ 匹配前面的子表達式一次或屢次。要匹配 + 字符,請使用 \+。
. 匹配除換行符 \n 以外的任何單字符。要匹配 . ,請使用 \. 。
[ 標記一箇中括號表達式的開始。要匹配 [,請使用 \[。
? 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 \?。
\ 將下一個字符標記爲或特殊字符、或原義字符、或向後引用、或八進制轉義符。例如, 'n' 匹配字符 'n'。'\n' 匹配換行符。序列 '\\' 匹配 "\",而 '\(' 則匹配 "("。
^ 匹配輸入字符串的開始位置,除非在方括號表達式中使用,此時它表示不接受該字符集合。要匹配 ^ 字符自己,請使用 \^。
{ 標記限定符表達式的開始。要匹配 {,請使用 \{。
| 指明兩項之間的一個選擇。要匹配 |,請使用 \|。

限定符

限定符用來指定正則表達式的一個給定組件必需要出現多少次才能知足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6種。

正則表達式組成

正則表達式能夠包含子表達式、小括號(子表達式部分)、中括號(主幹部分)、大括號(限定部分)。這些括號組合是比較靈活的,能夠相互包含(但大括號能不能包含其餘括號)。

源字符串:<div>a test</div>
正則表達式:(?<=<div>)[^<]+(?=</div>)
複製代碼

環視匹配

Lookaround, 也叫零寬斷言

  • 環視只進行子表達式的匹配,不佔有字符,匹配到的內容不保存到最終的匹配結果,是零寬度的。環視匹配的最終結果就是一個位置(肯定位置的過程)。
  • 環視的做用至關於對所在位置加了一個附加條件,只有知足這個條件,環視子表達式才能匹配成功。

示例1:

金額匹配: `(^0\.[0-9]{1,2}$)|(^[1-9]\d+\.[0-9]{1,2}$)|(^[1-9]\d+$)`
金額匹配(環視匹配): `(?!^0\d+|\D*0$)^[0-9]{1,7}(\.[0-9]{1,2})?$`
複製代碼

這裏常規金額匹配由三個子表達式組成,要排除整數部分爲0開頭的狀況,整個過程比較冗長。換成環視匹配後就簡單多了,環視匹配表達式的含義爲 匹配除0開頭的整數部分和非數字,整數部分長度1-7位。

優化金額 前:/^\d+(\.\d{1,2})?$/ 問題:12.校驗經過; 優化後:/^\d+[.]\d{1,2}$|^\d+$/ 有「.」 小數部分必填。

示例2:

源字符串:aa<p>one</p>bb<div>two</div>cc
正則表達式:<(?!/?p\b)[^>]+>
複製代碼

這個正則的意義就是匹配除了<p···>或

以外的全部標籤 按圖所示,這個正則中<就匹配它自己,(?!/?p\b)是一個順序否認表達式,子表達式是</?p\b,意思是這個表達式的右邊不能是字符【/p】或者【p】,問號是表明匹配一次或者不匹配,你們應該還記得。而後[^>]+中的[^···]是排除型字符組,表示的是除【>】之外的字符均可以匹配,匹配的數量是最少一次,最多不限制。最後一個表達式>的意義是匹配它自己。 上面整個表達式的含義就是:匹配【<(<右邊不能是p或/p)(除>的字符N個)>】這樣一個文本。由此例子,咱們也能夠看出,表達式一般能夠拆分紅一個個的子表達式,最後把它們連起來造成一個完整的表達式。

正序否認環視匹配

(?=Expression)
順序確定環視,表示所在位置右側可以匹配Expression
(?!Expression)
順序否認環視,表示所在位置右側不能匹配Expression
複製代碼

逆序環視匹配

(?<=Expression)
逆序確定環視,表示所在位置左側可以匹配Expression
(?<!Expression)
逆序否認環視,表示所在位置左側不能匹配Expression
複製代碼

開頭都是 "?"

都包含 「=」或「!」; 確定否認。(都包含確定」=」或 否認「!」)

逆序包含"<"

全局匹配模式和內聯匹配模式

內聯匹配模式特徵:正則前面的(?i)(?s)(?m)(?is)(?im)

稱爲內聯匹配模式,一般用內聯匹配模式代替使用枚舉值RegexOptions指定的全局匹配模式,寫起來更簡潔。

  • (?i)表示所在位置右側的表達式開啓忽略大小寫模式
  • (?s)表示所在位置右側的表達式開啓單行模式。
  • 更改句點字符(.)的含義,以使它與每一個字符(而不是除\n以外的全部字符)匹配。
  • 注意:(?s)一般在匹配有換行的文本時使用
  • (?m)表示所在位置右側的表示式開啓指定多行模式。
  • 更改^和$的含義,以使它們分別與任何行的開頭和結尾匹配,
  • 而不僅是與整個字符串的開頭和結尾匹配。
  • 注意:(?m)只有在正則表達式中涉及到多行的「^」和「$」的匹配時,才使用Multiline模式。
  • 上面的匹配模式能夠組合使用,好比(?is),(?im)。
  • 另外,還能夠用(?i:exp)或者(?i)exp(?-i)來指定匹配的有效範圍。

經常使用正則表達式練習

- 金額校驗包含最小最大值 ` ^0(?!\d+$)\.[0-9]?[1-9]{1}$|^2[0]{5}$|(?!^[0,2-9]\d+|\D*0$)^[0-9]{1,6}(\.[0-9]{1,2})?$`
- 手機號` ^1[3|5|8|6|9]\d{9}$ `  
- 身份證` err:\d{15}$|\d{17}[\d{1}|X|x]$; right:^\d{17}[\d|X|x]{1}$|^\d{15}$`
- 通常信息填寫:` ^([^\x00-\xff]|[A-Za-z0-9_-]|[()()]|[\\s])*$ `; //assic0-255除數字、大小寫字母、之外的字符、這個正則殺馬特字符是能夠輸入的
- 中文\英文\數字\下劃線 `^([\u4e00-\u9fa5]|[A-Za-z0-9_-])*$`  
- 各類電話號碼匹配,容許格式: 1398888888八、010-8888888八、010-88888888-88(轉接號)、400888888:`(^1[3|4|5|8|6|9]\d{9}$)|(^\d{3,4}-\d{7,8}(-\d{1,3})?$)|(^400\d{6}$)`
- 日期  `^[1,2]+[0-9]{3}-(0[1-9]|1[0,1,2])-(0[1-9]|([1,2][0-9]{1})|3[0,1]{1})$`
- 大於0的數 `/^[0-9]\d*(\.\d+)$/` => `/^[0-9]\d*(\.\d+)$/.test('1.0')`

1.驗證用戶名和密碼:("^[a-zA-Z]\w{5,15}$")正確格式:"[A-Z][a-z]_[0-9]"組成,而且第一個字必須爲字母6~16位;
2.驗證電話號碼:("^(\d{3,4}-)\d{7,8}$")正確格式:xxx/xxxx-xxxxxxx/xxxxxxxx;
3.驗證身份證號(15位或18位數字):("^\d{15}|\d{18}$");
4.驗證Email地址:("^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
5.只能輸入由數字和26個英文字母組成的字符串:("^[A-Za-z0-9]+$") ;
6.整數或者小數:^[0-9]+\.{0,1}[0-9]{0,2}$
7.只能輸入數字:"^[0-9]*$"。
8.只能輸入n位的數字:"^\d{n}$"。
9.只能輸入至少n位的數字:"^\d{n,}$"。
10.只能輸入m~n位的數字:。"^\d{m,n}$"
11.只能輸入零和非零開頭的數字:"^(0|[1-9][0-9]*)$"。
12.只能輸入有兩位小數的正實數:"^[0-9]+(.[0-9]{2})?$"。 => "^[0-9]+(\.[0-9]{2})?$"
13.只能輸入有1~3位小數的正實數:"^[0-9]+(.[0-9]{1,3})?$"。=> "^[0-9]+(\.[0-9]{1,3})?$"。
14.只能輸入非零的正整數:"^\+?[1-9][0-9]*$"。
15.只能輸入非零的負整數:"^\-[1-9][]0-9"*$。
16.只能輸入長度爲3的字符:"^.{3}$"。
17.只能輸入由26個英文字母組成的字符串:"^[A-Za-z]+$"。
18.只能輸入由26個大寫英文字母組成的字符串:"^[A-Z]+$"。
19.只能輸入由26個小寫英文字母組成的字符串:"^[a-z]+$"。
20.驗證是否含有^%&',;=?$\"等字符:"[^%&',;=?$\x22]+"。 21.只能輸入漢字:"^[\u4e00-\u9fa5]{0,}$" 22.驗證URL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"。 23.驗證一年的12個月:"^(0?[1-9]|1[0-2])$"正確格式爲:"01"~"09"和"1"~"12"。 24.驗證一個月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正確格式爲;"01"~"09"和"1"~"31"。 25.獲取日期正則表達式:\d{4}[年|\-|\.]\d{\1-\12}[月|\-|\.]\d{\1-\31}日? 評註:可用來匹配大多數年月日信息。 26.匹配雙字節字符(包括漢字在內):[^\x00-\xff] 評註:能夠用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1) 27.匹配空白行的正則表達式:\n\s*\r 評註:能夠用來刪除空白行 28.匹配HTML標記的正則表達式:<(\S*?)[^>]*>.*?</>|<.*? /> 網上流傳的版本太糟糕,上面這個也僅僅能匹配部分,對於複雜的嵌套標記依舊無能爲力 var regexp =/^([\u4e00-\u9fa5]|[A-Za-z0-9_-])*$/g; if(!regexp.test(content.trim())){ // 不符合正則 } - .*匹配除 \n 之外的任何字符。 - /[\u4E00-\u9FA5]/ 漢字 - /[\uFF00-\uFFFF]/ 全角符號 - /[\u0000-\u00FF]/ 半角符號 - Java不支持 ?、+、|、(),那應該怎麼實現呢? 首先要知道這件事,以後在java平臺寫正則時要看java的文檔 複製代碼

基礎手冊

記住經常使用符號是必要的,長時間不用忘記也很正常,查詢手冊在這裏

See Also

相關文章
相關標籤/搜索