正則表達式和它在前端的應用

序言

正則表達式,又叫規則表達式。把人類世界的一些字符規則以計算機可以理解的語言表達出來。Javascript提供了一個對象RegExp(Regular Expression)來管理和正則表達式相關的一切。javascript

 

建立方式

有兩種聲明正則對象的方法:html

  • 字面形式建立:reg = /pattern/attributes
  • new形式建立:reg = new RegExp(pattern, attributes)    // 簡寫方式更經常使用

其中,attributes表明該正則的屬性參數,可選值爲g, i, m,分別表明全局匹配,忽略大小寫,換行匹配。其中m在ECMAScript標準化以前不支持使用。前端

書寫規則

經常使用元字符

經常使用的正則匹配字符按功能能夠分爲「匹配字符」「匹配位置」和「量詞」。java

字符:git

  • .:匹配處換行符之外的任意字符
  • \w:匹配字母,數字,下劃線或漢字(word)
  • \s:匹配任意空格字符(空格,回車,Tab等)(space)
  • \d:匹配任意數字(digital)

位置:正則表達式

  • \b:匹配單詞首尾(單詞分隔符)
  • ^:匹配輸入字符串的開始
  • $:匹配輸入字符串的結束(在編寫校驗的時候必須加行首行尾)

量詞:express

  • {n,m}:重複n~m次
  • *:重複零次或更屢次,與{0,}相同
  • +:重複一次或更屢次,與{1,}相同
  • ?:重複0次或1次,與{0,1}相同

字符類

要想查找數字,字母或數字是很簡單的,由於已經有了對應這些字符集合的元字符,可是若是你想匹配沒有預約義元字符的字符集合(好比元音字母a,e,i,o,u),應該怎麼辦?數組

很簡單,你只須要在方括號裏列出它們就好了,像[aeiou]就匹配任何一個英文元音字母,[.?!]匹配標點符號(.或?或!)。前端工程師

咱們也能夠輕鬆地指定一個字符範圍,像[0-9]表明的含意與\d就是徹底一致的:一位數字;同理[a-z0-9A-Z_]也徹底等同於\w(若是隻考慮英文的話)。此外,最經常使用的還有檢測輸入是否含有中文,使用[\u4e00-\u9fa5]。測試

字符類還能夠用[^a]來匹配任何除了a之外的字符。

分支條件

正則表達式裏的分枝條件指的是有幾種規則,若是知足其中任意一種規則都應該當成匹配,具體方法是用|把不一樣的規則分隔開。

\d{5}-\d{4}|\d{5}這個表達式用於匹配美國的郵政編碼。美國郵編的規則是5位數字,或者用連字號間隔的9位數字。之因此要給出這個例子是由於它能說明一個問題:使用分枝條件時,要注意各個條件的順序。若是你把它改爲\d{5}|\d{5}-\d{4}的話,那麼就只會匹配5位的郵編(以及9位郵編的前5位)。緣由是匹配分枝條件時,將會從左到右地測試每一個條件,若是知足了某個分枝的話,就不會去再管其它的條件了。

反義

有時須要查找不屬於某個能簡單定義的字符類的字符。好比想查找除了數字之外,其它任意字符都行的狀況,這時須要用到反義:

  • \W:匹配字母、數字、下劃線、漢字之外的字符 ([^a-zA-Z0-9])
  • \S:匹配不是空格字符的字符
  • \D:匹配任何非數字的字符
  • \B:匹配不是單詞開頭或結束的位置
  • [^x]:匹配除x之外的字符
  • [^abcde]:匹配除abcde之外的字符

後向引用

若是咱們須要重複匹配多個字符,能夠用小括號將須要的部分括起,指定子表達式(分組)。使用小括號指定一個子表達式後,匹配這個子表達式的文本(也就是此分組捕獲的內容)能夠在表達式或其它程序中做進一步的處理。默認狀況下,每一個分組會自動擁有一個組號,規則是:從左向右,以分組的左括號爲標誌,第一個出現的分組的組號爲1,第二個爲2,以此類推。

好比咱們要匹配相似go go或kitty kitty的重複出現的字符,就可使用如下匹配方式:\b(\w+)\b\s+\1\b。

 

經常使用的分組語法以下:

  • (exp):匹配exp,並對捕獲文本自動命名爲\1,\2...
  • (?<name>exp):匹配exp,將捕獲問文本以name命名,經過\k<name>來引用該匹捕獲文本
  • (?:exp):匹配exp,不捕獲匹配的文本,也不給此分組分配組號

由第二條,咱們能夠獲得上面正則的另外一種表現形式:\b(?<Word>\w+)\b\s+\k<Word>\b。

零寬斷言

零寬斷言用於查找在前面或後面知足某種條件的字段(但不包括先後知足匹配的那部分),也就是說它們像\b,^,$那樣用於指定一個位置,這個位置應該知足必定的條件(即斷言),所以它們也被稱爲零寬斷言。

(?=exp)也叫零寬度正預測先行斷言,它斷言自身出現的位置的後面能匹配表達式exp。好比\b\w+(?=ing\b),匹配以ing結尾的單詞的前面部分(除了ing之外的部分),如查找I'm singing while you're dancing.時,它會匹配sing和danc。

(?<=exp)也叫零寬度正回顧後發斷言,它斷言自身出現的位置的前面能匹配表達式exp。好比(?<=\bre)\w+\b會匹配以re開頭的單詞的後半部分(除了re之外的部分),例如在查找reading a book時,它匹配ading。

注:JS引擎不支持這種正則表達方式。由於這種方式效率不高,推薦使用分組進行匹配。

負向零寬斷言

負向零寬斷言用於查找在前面或後面不知足某種條件的字段(但不包括先後知足匹配的那部分)。此處要與反義字符作區分。例如,若是咱們想查找這樣的單詞--它裏面出現了字母q,可是q後面跟的不是字母u,咱們能夠嘗試這樣:

\b\w*q[^u]\w*\b匹配包含後面不是字母u的字母q的單詞。可是若是多作測試(或者你思惟足夠敏銳,直接就觀察出來了),你會發現,若是q出如今單詞的結尾的話,像Iraq,Benq,這個表達式就會出錯。這是由於[^u]總要匹配一個字符,因此若是q是單詞的最後一個字符的話,後面的[^u]將會匹配q後面的單詞分隔符(多是空格,或者是句號或其它的什麼),後面的\w*\b將會匹配下一個單詞,因而\b\w*q[^u]\w*\b就能匹配整個Iraq fighting。負向零寬斷言能解決這樣的問題,由於它只匹配一個位置,並不消費任何字符。如今,咱們能夠這樣來解決這個問題:\b\w*q(?!u)\w*\b。

零寬度負預測先行斷言(?!exp),斷言此位置的後面不能匹配表達式exp。例如:\d{3}(?!\d)匹配三位數字,並且這三位數字的後面不能是數字;\b((?!abc)\w)+\b匹配不包含連續字符串abc的單詞。

同理,咱們能夠用(?<!exp),零寬度負回顧後發斷言來斷言此位置的前面不能匹配表達式exp:(?<![a-z])\d{7}匹配前面不是小寫字母的七位數字。

這有一個用於匹配沒有內聯樣式的HTML標籤中的內容(不匹配標籤):(?<=<(\w+)>).*(?=<\/\1>)。這個表達式最能表現零寬斷言的真正用途。

註釋

小括號的另外一種用途是經過語法(?#comment)來包含註釋。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。

貪婪匹配與懶惰匹配

正則有一個特色——貪婪。它會匹配儘量多的東西。好比當我想將<div><bold>標題</bold>文本</div>中的標籤用空格替換掉,若是使用/<.+>/則會使整段文本被替換,由於正則會匹配儘量多的字符。那麼應該如何讓正則匹配儘量少的字符呢?這時候就須要使用「懶惰匹配」。只須要在量詞(*+[2,4])後面加一個問號,就可讓正則匹配儘量少的字符。針對上面的例子就應該使用/<.+?>/

ps: 本例也能夠用/<[^<>]+>/來實現。

 

經常使用方法

RegExp對象的方法

  • regexp.test(string):用來檢測傳入字符串中是否有正則匹配項,若是有,返回true,不然返回false
  • regexp.exec(string, 'g'):匹配正則表達式而且返回匹配的字段數組。

String對象的方法

0. 常見的字符串操做

var str = 'abcdef'; 

str.search('b'); // 1
str.substring(1,4)  //"bcd"
str.charAt(0);  //"a"

var str = 'abc-12-u-qw';
var arr = str.split('-');
alert(arr);  //["abc", "12", "a", "qu"]

1. 字符串的正則(規則)操做

var str = 'abc 12 as23 1';

str.search(/\d/);  //4
str.match(/\d+/g);  //["12", "23", "1"]
str.replace(/a/g, 'T');    // 'Tbc 12 Ts23 1'

ps: replace()與正則表達式應用實例——過濾敏感詞與提取HTML標籤內的純文本

match()和exec()的不一樣 

在非全局匹配時,str.match(reg)和reg.exec(str)都能實現分組匹配,然而當進行全局匹配時,exec可以記錄上次匹配的索引,繼續進行匹配。此時一般結合循環使用,事例以下:

var s = 'aaalllsss0tAAAnnn999';
var re1 = /((\w)\2{2})(\w)\3{2}/g;
var res;

while(res=re1.exec(s)) {
  console.log("match result: " + res[1]};
  console.log("re1.lastindex: " + re1.lastIndex);
  console.log("remain string: " + s.slice(re1.lastIndex));
}

?的四種用法

 

  1. 在表示正常字符時,需進行轉義\?
  2. 表示數量,0或1
  3. 放在量詞後,表示去貪婪匹配,即匹配最小數量
  4. 放在括號內,表示不捕捉模式(?:exp)

參考文章

正則表達式30分鐘入門教程

相關文章
相關標籤/搜索