溫故js系列(5)-正則表達式&經常使用代碼

前端學習:教程&開發模塊化/規範化/工程化/優化&工具/調試&值得關注的博客/Git&面試-前端資源彙總javascript

歡迎提issues斧正:正則表達式前端

JavaScript-正則表達式

正則表達式簡述

正則表達式(regular expression)描述了一種字符串匹配模式,能夠用來檢查一個字符串是否含有某類字符串、將匹配的字符串作替換或者從某個字符串中取出符合某個條件的字符串等。ECMAScript的RegExp對象表示正則表達式,而String 和RegExp 都定義了使用正則表達式進行強大的模式匹配和文本檢索與替換的函數。java

正則表達式修飾符

參數       含義                           備註
i       忽略大小寫
g       全局匹配
m       多行匹配
u       正確處理四個字節的UTF-16編碼       ES6新增
y       確保匹配必須從剩餘的第一個位置開始   ES6新增

正則表達式建立

建立正則表達式和建立字符串相似,建立正則表達式提供了兩種方法,一種是採用new
運算符,另外一個是採用字面量方式。git

var xzavier = new RegExp('xzavier');       //第一個參數字符串
var xzavier = new RegExp('xzavier', 'ig'); //第二個參數可選修飾符
var xzavier = /xzavier/;                   //直接用兩個反斜槓
var xzavier = /xzavier/ig;                 //第二個斜槓後面加上的是修飾符

和對象數組等同樣,咱們一致推崇使用字面量的方式。簡便快捷。可是也有必須使用new的方式,
當你的正則表達式中含有變量的時候:es6

var reg = 'v';
var pattern = new RegExp('xza' + reg + 'ier'); // 這時候就不能使用字面量的方式了

正則表達式方法

RegExp 對象的test() 方法在字符串中查找是否存在指定的正則表達式並返回布爾值,若是存在則返回true,不存在則返回false。github

var pattern = new RegExp('xzavier', 'i');  //正則模式,不區分大小寫
var pattern1 = /xzavier/i; //建立正則模式,不區分大小寫
var str = 'This is Xzavier!'; 
console.log(pattern.test(str));  //true
console.log(pattern1.test(str));  //true
console.log(/xzavier/i.test(str));  //true

RegExp 對象的exec()方法也用於在字符串中查找指定正則表達式,若是exec()方法執行成
功,則返回包含該查找字符串的相關信息數組。若是執行失敗,則返回null。面試

var pattern = new RegExp('xzavier', 'i'); 
var pattern1 = /xzavier/i; 
var str = 'This is Xzavier!'; 
console.log(pattern.exec(str));  //["Xzavier"]
console.log(pattern1.exec(str));  //["Xzavier"]
console.log(/xzavier1/i.exec(str));  //null

String 對象也提供了4 個使用正則表達式的方法。
match(pattern) 返回pattern中的匹配的字符串或null:正則表達式

var pattern = /xzavier/ig;   //全局匹配
var str = 'This is Xzavier, this is Xzavier too.'; 
console.log(str.match(pattern));  //["Xzavier", "Xzavier"]
console.log(str.match(pattern).length);  //2
console.log('javascript'.match(/xzavier/ig));  //null

replace(pattern, replacement) 用replacement替換pattern:express

var pattern = /xzavier/ig;  
var str = 'This is Xzavier, this is Xzavier too.'; 
console.log(str.replace(pattern, 'JavaScript'));  //This is JavaScript, this is JavaScript too.

search(pattern) 返回字符串中pattern開始位置,查找到返回位置,不然返回-1:數組

var pattern = /xzavier/i;  
var str = 'This is Xzavier, this is Xzavier too.'; 
var str1 = 'This is JavaScript, this is JavaScript too.'; 
console.log(str.search(pattern));   //8
console.log(str1.search(pattern));   //-1

split(pattern) 返回字符串按指定pattern 拆分的數組:

var pattern = / /ig;  
var str = 'This is Xzavier, this is Xzavier too.'; 
console.log(str.split(pattern));   //["This", "is", "Xzavier,", "this", "is", "Xzavier", "too."]

RegExp對象的靜態屬性

屬性              短名      含義
input             $_    當前被匹配的字符串
lastMatch         $&    最後一個匹配字符串
lastParen         $+    最後一對圓括號內的匹配子串
leftContext       $`    最後一次匹配前的子串
rightContext      $'    在上次匹配以後的子串

var pattern = /(x)zavier/;
var str = 'This is xzavier!';
pattern.test(str); 
console.log(RegExp.input); //This is xzavier!
console.log(RegExp.leftContext); //This is 
console.log(RegExp.rightContext); //!
console.log(RegExp.lastMatch); //xzavier
console.log(RegExp.lastParen); //x

RegExp對象的實例屬性

屬性                   含義
global       Boolean值,表示g是否已設置
ignoreCase   Boolean 值,表示i 是否已設置
lastIndex    整數,表明下次匹配將從哪裏字符位置開始
multiline    Boolean值,表示m是否已設置
Source       正則表達式的源字符串形式

var pattern = /xzavier/ig;
console.log(pattern.global); //true,是否設置了全局
console.log(pattern.ignoreCase); //true,是否設置了忽略大小寫
console.log(pattern.multiline); //false,是否設置了換行
console.log(pattern.lastIndex); //0,下次匹配位置
console.log(pattern.source); //xzavier,正則表達式的源字符串

正則表達式元字符

字符類:單個字符和數字

clipboard.png

說一下/\./ 和 /[.]/ 只能匹配'.',不匹配通配符

\\ 引用符,用來將這裏列出的這些元字符看成普通的字符來進行匹配。如.用來匹配點字符,而不是任何字符的通配符。

[ ],[c1-c2],[^c1-c2]
  字符組,匹配括號中的任何一個字符,並非要所有匹配。如/x[zav]e/匹配xze、xae和xve,可是不匹配xxe。如/[0-9]/能夠匹配任何數字字符;如/[A-Za-z]/能夠匹配任何大小寫字母。如正則表達式[^269A-Z] 將匹配除了二、六、9和全部大寫字母以外的任何字符。

對於這兩個操做符,特殊符號沒有絕對規律,卻是特殊字母匹配符仍是有規律的,見下

'love.'.replace(/./, '');  //"ove."  通配
'love.'.replace(/\./, '');  //"love"  點
'love.'.replace(/[.]/, ''); //"love"  點
'love.'.replace(/[\.]/, ''); //"love"  點

可是:

'lo v^se.'.replace(/\^/, ''); //"lo vse."  匹配^
'lo v^se.'.replace(/[^]/, '');  //"o v^se." 匹配開始去了,並無匹配^
'lo v^se.'.replace(/[\^]/, ''); //"lo vse." 要加一個這樣才匹配^


'lo vse.'.replace(/\s/, '');  //"lovse." 匹配空格
'lo vse.'.replace(/[s]/, ''); //"lo ve."  匹配字母
'lo vse.'.replace(/[\s]/, '');  //"lovse."  要加一個\才匹配空格

'    lovte.'.replace(/\t/, '');  //"lovte. 匹配製表符
'    lovte.'.replace(/[t]/, ''); //"    love."  匹配字母
'    lovte.'.replace(/[\t]/, '');  //"lovte."  要加一個\才匹配製表符

字符類:空白字符

clipboard.png

\b是匹配字符串開頭結尾及空格回車等的位置,單詞邊界, 不會匹配空格符自己。\s則是匹配空白字符自己、空格符自己、換行符自己。

字符類:錨字符

clipboard.png

字符類:重複字符

clipboard.png

字符類:替代字符

a|b|c    匹配a或b或c中的任意一個

字符類:記錄字符

$n     與 regexp 中的第 n(1~99) 個子表達式相匹配的文本
$&     表示與 regexp 相匹配的子串
$`     位於匹配子串左側的文本
$'     位於匹配子串右側的文本
$$     直接量符號

'you are beautiful'.replace(/beautiful/g, 'so $&');  //"you are so beautiful"
'leftright'.replace(/right/, '$`');  //"leftleft"
'leftright'.replace(/left/, "$'");  //"rightright"

貪婪模式和惰性模式

貪婪  惰性
'+'   +?
?     ??
\*    *?
{n}   {n}?
{n,}  {n,}?
{n,m} {n,m}?

var pattern = /[a-z]+/; //貪婪匹配,所有替換
var str = 'qqqwwweee';
var result = str.replace(pattern, 'xxx');
console.log(result);  //xxx

var pattern = /[a-z]+?/; //?號關閉了貪婪匹配,只替換了第一個
var str = 'qqqwwweee';
var result = str.replace(pattern, 'xxx');
console.log(result);  //xxxqqwwweee

斷言

先行斷言: x(?=y),找到x後面緊跟着y的位置,若是找到則匹配這個位置

var pattern = /(xza(?=vier))/; //xza後面必須跟着vier才能捕獲
var str = 'hello,xzavier';
console.log(pattern.test(str));  //true

先行否認斷言 x(?!y),找到x後面不是y的位置,若是找到則匹配這個位置

var pattern = /(xza(?!vier))/; //xza後面必須跟着的不是vier才能捕獲
var str = 'hello,xzaqqqvier';
console.log(pattern.test(str));  //true

惋惜,JavaScript不支持 後行斷言 和 後行否認斷言。
固然,如今不支持,不表明將來不支持。雖然外面最新的ES6也沒有推出正式的標準,可是已經有了提案,ES7中應該會推出標準實現 後行斷言 和 後行否認斷言。
屆時咱們可能就能用到這兩個功能,這樣的代碼了:

var pattern = /(?=xza)vier/; //vier前面必須是xza才能捕獲
var str = 'hello,xzavier';
console.log(pattern.test(str));  //true

var pattern = /(?!xza)vier)/; //vier前面必須不是xza才能捕獲
var str = 'hello,xzaqqqvier';
console.log(pattern.test(str));  //true

這代碼如今是不能使用的,可是咱們想要實現相似的功能,用別的方式,多寫兩行代碼也就實現了。

捕獲性分組和非捕獲性分組

捕獲性分組

var pattern = /(\d+)([a-z])/; //捕獲性分組
var str = '123abc';
console.log(pattern.exec(str));  //["123a", "123", "a"]

非捕獲性分組 格式: (?:x)

var pattern = /(\d+)(?:[a-z])/; //非捕獲性分組
var str = '123abc';
console.log(pattern.exec(str));  //["123a", "123"]

經常使用正則表達式

親測有效:

匹配中文字符: [\u4e00-\u9fa5]
匹配Email地址:\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/
去除首尾空白:/(^\s*)|(\s*$)/g
去除多餘空格:/\s/g
身份證:\d{17}[\d|x]|\d{15}
ip地址:\d+\.\d+\.\d+\.\d+
網址URL: ^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+
QQ號:[1-9]{4,}
數字串千分法:

function commafy(num){
      return num && num
          .toString()
          .replace(/(\d)(?=(\d{3})+\.)/g, function($1, $2){
              return $2 + ',';
          });
  }
  commafy(1234567.002);
  // 1,234,567.002"

判斷手機app內置瀏覽器:

var ua = navigator.userAgent.toLowerCase(),
    isWx = /microMessenger/i.test(ua),
    isQQ = /\s+qq\//ig.test(ua),
    isQZone = /qzone/i.test(ua),
    isWeibo = /weibo/i.test(ua);

首字母大寫:

str = "hello woRld";
String.prototype.initCap = function () {
   return this.toLowerCase().replace(/(?:^|\s)[a-z]/g, function (s) {
      return s.toUpperCase();
   });
};
console.log(str.initCap());  //Hello World

"yyyy-mm-dd" 格式的日期校驗(平閏年):

function testDate(str) {
    var reg = /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/;
    return reg.test(str);
}
testDate('2016-03-12'); //true
testDate('2016-23-12'); //false
testDate('2016-02-29'); //true
testDate('2017-02-29'); //false

延伸閱讀:正則表達式的擴展
測試:在線正則表達式測試

相關文章
相關標籤/搜索