迅速掌握正則表達式

1.前言

提到正則,可能不少人會和我之前同樣,第一時間會感到很頭疼,此篇文章的目的不在於讓你們變成正則高手,僅僅只是敘述一些簡單正則的寫法如何寫一些簡單正則,一塊兒加油吧!html

2.正文

2.1 福利章節

首先放出寫正則的經常使用API表,畢竟做爲一個api工程師,看api很重要!正則表達式

字符組匹配

量詞匹配

位置匹配

括號做用

修飾符

API表看完,咱們正則就學會了一半了!api

2.2 認識模糊匹配

正則的精確匹配意義不大,大部分是模糊匹配,其中有兩種方式:橫向和縱向匹配
1.橫向匹配學習

// 表示匹配:第一個字符是 "a"
// 接下來是 2 到 5 個字符 "b",
// 最後是字符 "c"。
const r = /ab{2,5}c/

2.縱向匹配spa

// 此時能夠匹配'a1b'或者'a2b'或者'a3b'
const r = /a[123]b/

既然學了,那麼確定是爲了能用到,那麼此時咱們能夠作哪些事情?那咱們能夠作太多事了,基本上掌握了字符組和量詞就能夠應付大部分的簡單正則了。code

咱們使用反向學習法,先看題分析,帶着疑問去看api表,能夠讀懂正則以後再加上練習就等於掌握htm

Q1:圖片

const r = /\d{m,n}/

解析:首先咱們看\d,意思表明匹配數字,{m,n}是量詞,表明的是匹配次數。那麼此題的意思就是匹配m到n個數字ip

Q2:rem

const r = /[A-Za-z0-9]+/

解析:[A-Za-z0-9]表明匹配英文字母和數字,+表明1次及以上,此題的意思就是:匹配1次及以上的字母或數字

Q3: 匹配16進制顏色

const regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;

解析:16進制可能會是6位#FFFFFF 也多是3位 #FFF,這邊纔有縱向匹配,使用量詞{6}{3} 加上管道符便可。圖片解析以下:

2.3 正則匹配位置

在ES5中,共有 6 個錨:
^、$、\b、\B、(?=p)、(?!p),經常使用的有以下2個:

2.31 ^ 和 $

  • ^(脫字符)匹配開頭,在多行匹配中匹配行開頭。
  • $(美圓符號)匹配結尾,在多行匹配中匹配行結尾。

作題環節:

Q1:

var result = "hello".replace(/^|$/g, '#');
console.log(result);
// => "#hello#"

Q2:不匹配任何字段

const r = /.^/

解析:由於此正則要求只有一個字符,但該字符後面是開頭,而這樣的字符串是不存在的。

2.32 \b 和 \B

\b 是單詞邊界,具體就是 \w\W 之間的位置,也包括 \w^ 之間的位置,和 \w$ 之間的位置。

var result = "[JS] Lesson_01.mp4".replace(/\b/g, '#');
console.log(result);
// => "[#JS#] #Lesson_01#.#mp4#"

解析:\w 是字符組 [0-9a-zA-Z_] 的簡寫形式,而 \W 是排除字符組 1 的簡寫形式。

  • 第 1 個,兩邊字符是 "[" 與 "J",是 \W 與 \w 之間的位置
  • 第 2 個,兩邊字符是 "S" 與 "]",也就是 \w 與 \W 之間的位置
  • 第 3 個,兩邊字符是空格與 "L",也就是 \W 與 \w 之間的位置。
  • 第 4 個,兩邊字符是 "1" 與 ".",也就是 \w 與 \W 之間的位置。
  • 第 5 個,兩邊字符是 "." 與 "m",也就是 \W 與 \w之間的位置。
  • 第 6 個,位於結尾,前面的字符 "4" 是 \w,即 \w 與 $ 之間的位置。

\b 的概念理解了,\B 的概念也就很好理解了,\B 就是 \b 的反面的意思,

var result = "[JS] Lesson_01.mp4".replace(/\B/g, '#');
console.log(result);
// => "#[J#S]# L#e#s#s#o#n#_#0#1.m#p#4"

2.33 (?=p) 和 (?!p)

(?=p),其中 p 是一個子模式,即 p 前面的位置,或者說,該位置後面的字符要匹配 p。
好比 (?=l),表示 "l" 字符前面的位置:

var result = "hello".replace(/(?=l)/g, '#');
console.log(result);
// => "he#l#lo"

而 (?!p) 就是 (?=p) 的反面意思:

var result = "hello".replace(/(?!l)/g, '#');
console.log(result);
// => "#h#ell#o#"

作題環節:

Q3:數字的千分位表示

var result = "12345678".replace(/(?=(\d{3})+$)/g, ',')
console.log(result);
// => "12,345,678"

解析:其中(?=(\d{3}) 表明匹配位置在3位數字的前面+$表明最少出現一次。g全局匹配

乍一看,咱們這個正則是寫完了,其實否則,寫完正則要多測幾組,就會發現問題

var result = "123456789".replace(/(?=(\d{3})+$)/g, ',')
console.log(result);
// => ",123,456,789"

這是由於咱們的正則從結尾向前數,一可是 3 的倍數,就把其前面的位置替換成逗號。這個解決方法其實很簡單,咱們只要不匹配開頭不就行了,匹配開頭咱們知道用^,那不匹配呢?用(?!^)
正則修改以下:

var regex = /(?!^)(?=(\d{3})+$)/g;
var result = "12345678".replace(regex, ',')
console.log(result);
// => "12,345,678"
result = "123456789".replace(regex, ',');
console.log(result);
// => "123,456,789"

加大難度

Q4:密碼長度 6-12 位,由數字、小寫字符和大寫字母組成,但必須至少包括 2 種字符。
不考慮「但必須至少包括 2 種字符」這一條件。咱們能夠容易寫出:

var regex = /^[0-9A-Za-z]{6,12}$/;

若是必需要包含數字呢:

var regex = /(?=.*[0-9])^[0-9A-Za-z]{6,12}$/;

咱們只需明白(?=.*[0-9])^,分開來看就是 (?=.*[0-9])^。表示開頭前面還有個位置(固然也是開頭,即同一個位置)。(?=.*[0-9]) 表示該位置後面的字符匹配 .*[0-9],即,有任何多個任意字符,後面再跟個數字。就是接下來的字符,必須包含個數字。

最終答案:

// 解法1:
var regex = /((?=.*[0-9])(?=.*[a-z])|(?=.*[0-9])(?=.*[A-Z])|(?=.*[a-z])(?=.*[A-Z]))^[0-9A-Za-z]{6,12}$/;
// 解法2:
var regex = /(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[0-9A-Za-z]{6,12}$/;

你們能夠好好讀一下,思考兩種解法的意思。

2.4 分組

簡單點說分組就是括號

直接作題

Q1:把 yyyy-mm-dd 格式,替換成 mm/dd/yyyy

var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, "$2/$3/$1");
console.log(result);
// => "06/12/2017"

解析:其中 replace 中的,第二個參數裏用 $1$2$3 指代相應的分組。

Q2:一個正則支持匹配以下三種格式:`2016-06-12
2016/06/12
2016.06.12`

很容易有以下答案

var regex = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // true

其中 /. 須要轉義。雖然匹配了要求的狀況,但也匹配 "2016-06/12" 這樣的數據。修改以下:

var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // false

可視化形式以下:

注意裏面的 \1,表示的引用以前的那個分組 (-|\/|\.)。無論它匹配到什麼,\1 都匹配那個一樣的具體某個字符。

括號嵌套 以左括號(開括號)爲準

var regex = /^((\d)(\d(\d)))\1\2\3\4$/;
var string = "1231231233";
console.log( regex.test(string) ); // true
console.log( RegExp.$1 ); // 123
console.log( RegExp.$2 ); // 1
console.log( RegExp.$3 ); // 23
console.log( RegExp.$4 ); // 3

可視化形式以下:

Q3:字符串 trim 方法模擬。
trim 方法是去掉字符串的開頭和結尾的空白符

// 解法1:匹配到開頭和結尾的空白符,而後替換成空字符
function trim(str) {
  return str.replace(/^\s+|\s+$/g, ''); }
console.log( trim(" foobar ") );
// => "foobar

// 解法2:匹配整個字符串,而後用引用來提取出相應的數據
function trim (str) {
  return str.replace(/^\s*(.*?)\s*$/g, "$1"); }
console.log( trim(" foobar ") );
// => "foobar"

Q4:將每一個單詞的首字母轉換爲大寫

function titleize (str) {
  return str.toLowerCase().replace(/(?:^|\s)\w/g, function (c) {
  return c.toUpperCase();
  }); }
console.log( titleize('my name is epeli') );
// => "My Name Is Epeli"

Q5: HTML 轉義和反轉義

// 將HTML特殊字符轉換成等值的實體
function escapeHTML (str) {
  var escapeChars = {
  '<' : 'lt',
  '>' : 'gt',
  '"' : 'quot',
  '&' : 'amp',
  '\'' : '#39'
  };
  return str.replace(new RegExp('[' + Object.keys(escapeChars).join('') +']', 'g'),
function (match) {
  return '&' + escapeChars[match] + ';';
  }); }
console.log( escapeHTML('<div>Blah blah blah</div>') );
// => "&lt;div&gt;Blah blah blah&lt;/div&gt";

// 實體字符轉換爲等值的HTML。
function unescapeHTML (str) {
  var htmlEntities = {
  nbsp: ' ',
  lt: '<',
  gt: '>',
  quot: '"',
  amp: '&',
  apos: '\''
  };
  return str.replace(/\&([^;]+);/g, function (match, key) {
  if (key in htmlEntities) {
  return htmlEntities[key];
  }
  return match;
  }); }
console.log( unescapeHTML('&lt;div&gt;Blah blah blah&lt;/div&gt;') );
// => "<div>Blah blah blah</div>"

3. 結尾

其實到這裏,基本上經常使用的正則api都已經出現了,剩下的就是活學活用了,你們能夠在工做中某些之前用js的api的地方如今換成正則,即裝b,又能夠更好的掌握正則。

因爲本人技術有限,如文內有錯誤,還望指出,感謝!

參考文章:《JavaScript正則表達式迷你書》


  1. 0-9a-zA-Z_
相關文章
相關標籤/搜索