JS中的正則表達式&&全面梳理|內附思惟導圖

正則表達式,又稱規則表達式。(英語:Regular Expression,在代碼中常簡寫爲regex、regexp或RE)javascript

用來處理字符串的規則html

  • 只能處理字符串
  • 它是一個規則:能夠驗證字符串是否符合某個規則(test),也能夠把字符串中符合規則的內容捕獲到(exec / match...)
let str = "good good study , day day up!";
//=>學正則就是用來制定規則(是否包含數字)
let reg = /\d+/;
reg.test(str); //=>false

str = "2020-04-07";
reg.exec(str); //=>["2020",index:0,inputs:"原始字符串"]
複製代碼

1、正則基礎(RegExp)

一、定義

定義:是一種處理字符串的規則java

  • JS中的正則 是一種引用數據類型

二、正則的編寫方式

構造函數由於傳遞的是字符串,\須要寫兩個才表明斜槓es6

  • 字面量方式:let reg = /\d+/g;
  • 實例的方式:let reg = new RegExp("\\d+","g");
    • 當正則中的一些字符須要是變量的時候;纔會選擇這種方式

兩種方式的區別

  • 正則表達式中的部份內容是變量存儲的值時
//1.兩個斜槓中間包起來的都是元字符(若是正則中要包含某個變量的值,則不能使用字面量方式建立)
let type = "xiaozhima";
reg = /^@"+type+"@$/; 
console.log(reg.test("@xiaozhima@")); //=>false
console.log(reg.test('@"""typeeeee"@')); //=>true

//2.這種狀況只能使用構造函數方式(由於它傳遞的規則是字符串,只有這樣才能進行字符串拼接)
reg = new RegExp("^@"+type+"@$");
console.log(reg.test("@xiaozhima@"));//=>true
複製代碼

三、正則的用途

正則RegExp.prototype上的方法正則表達式

  • 匹配 test
  • 捕獲 exec
  • 匹配 test
    • 編寫一個正則(制定了一套規則):去測試某一個字符串是否符合這個規則;
  • 捕獲 exec
    • 編寫一個正則(制定了一套規則):去把某個字符串中符合這個規則的字符獲取到

字符串String.prototype上支持正則表達式處理的方法數組

  • replace
  • match
  • splite
  • .......

四、正則的組成(只列舉一些經常使用的)

正則表達式由一些修飾符和一些元字符(metacharacters)組成。markdown

  • 元字符則由普通字符和一些特殊字符組成:
    • 普通字符包括大小寫的字母和數字,
    • 特殊元字符則具備特殊的含義,咱們下面會給予解釋。

-1).修飾符

用在正則外邊的:ide

  • 例如:/abc/i裏的i
字符 含義 英文全稱
i 忽略大小寫 ignoreCase
m 多行匹配 multiline
g 全局匹配 global
s 讓「點」能匹配任意字符,包含 \n 和 \r
...... ......

-2).元字符

斜槓中間的 內容 咱們稱爲元字符函數

  • 例如:/abc/i裏的abc

普通元字符

就是普通的大小寫的字母和數字;工具

特殊元字符

有特殊含義的元字符

字符 含義
\ 轉義字符(把有特殊含義的字符轉換成字符自己,也能夠把普通字符轉義成有特殊含義的字符)
\d 0~9之間的數字
\D 除了0~9 以外的任意字符
\w 數字、字母、下劃線(小寫w)
\W 除了 數字、字母、下劃線 的任意字符(大寫W)
^ 以什麼字符開頭
$ 以什麼字符結尾
. 表明除了換行之外的全部字符
\n 表明換行
\s 一個空白字符(包含空格、製表符、換行符等)
\t 一個製表符(一個TAB鍵:4個空格)
\b 匹配一個單詞的邊界
---- ----
x|y 表明 或;x或y
[xyz] 表明 或;x或y或z (與上一個的區別是:[]中先後只能寫單個字符,而|先後能夠是一組數)
[^xy] 除了xy的任意字符
[a-z] a~z 的任意字符 小寫的英文字母
[^a-z] 除了a-z 的任意字符
() 分組和提高優先級
(?:) 只匹配不捕獲
(?=) 正向確定預查
(?!) 正向否認預查
...... ......

量詞元字符

都是用在其餘元字符後面的

  • 例如:/abc{3}/ => {3}
字符 含義
前面的字符出現 0 或者 1 次 便可
+ 前面的字符出現 1 次或 屢次 便可
* 前面的字符出現 0 或 屢次 便可
{n} 前面的字符連續出現 n 次 便可
{n,m} 前面的字符連續出現 n 到 m 次 便可
{n,} 前面的字符連續出現 n 到 屢次 便可
...... ......

思惟導圖:正則基礎

2、正則的匹配(test)

編寫一個正則(制定了一套規則):去測試某一個字符串是否符合這個規則;

一、語法

  • 正則.test(字符串)

二、返回值

  • 符合正則規則:返回TRUE
  • 不符合正則規則:返回FALSE

三、一些例子🌰練習

\d,?,{n,m}的相關練習

var str = '小芝麻666';
var reg = /\d/; // 只要字符串中含有數字 便可
console.log(reg.test(str)) // true 
console.log(reg.test('werwf2ergdfg'))//true
console.log(reg.test('aefasdfsdfsf'))//false
console.log(reg.test('3453245254')) // true 

var reg = /\d?/; // 數字出現0或1次 字符串有沒有數字都知足狀況
console.log(reg.test('xiaozhima666')) // true
console.log(reg.test('werwf2ergdfg'))//true
console.log(reg.test('aefasdfsdfsf'))//true
console.log(reg.test('3453245254')) // true


var reg = /\d{2,4}/; // 字符串中有沒有連續2個或者3個數字 或者4個數字
// /\d\d/ /\d\d\d/ /\d\d\d\d/
console.log(reg.test('xiaozhima666')) // true
console.log(reg.test('werwf2ergdfg'))//false
console.log(reg.test('aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 


var reg = /\d{2}/; // 字符串中 有兩個連續的數字 便可
console.log(reg.test('xiaozhima666')) // true
console.log(reg.test('werwf2e3rgdfg'))// false
console.log(reg.test('aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 
複製代碼

開頭^ 和 結尾$ 的相關練習

  • 正則中有 ^ $ : 字符串必須所有知足正則
  • 正則中沒有 ^ $ : 只要字符串中有符合這個正則的字符便可
var reg = /^\d/; // 要求字符串是 以數字開頭的
console.log(reg.test('xiaozhima666')) // false
console.log(reg.test('werwf2e3rgdfg'))// false
console.log(reg.test('aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 


var reg = /^\d{2,3}/; // 要求 字符串 是以 兩個或者三個數字開頭的 便可
console.log(reg.test('1xiaozhima666')) // false
console.log(reg.test('22werwf2e3rgdfg'))// true
console.log(reg.test('432aefasdfsdfsf'))// true
console.log(reg.test('3453245254')) // true



var reg = /d{2,3}/; //字符串中 須要有連續兩到三個d
console.log(reg.test('1xiaozhima666')) // false
console.log(reg.test('22werwf2e3rgdfg'))// false
console.log(reg.test('432aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // false


var reg = /\d$/; // 字符串須要是一個 數字 結尾的字符
console.log(reg.test('1xiaozhima666')) // true
console.log(reg.test('22werwf2e3rgdfg'))// false
console.log(reg.test('432aefasdfsdfsf'))// false
console.log(reg.test('3453245254')) // true 


var reg = /\d{4,6}$/; // 以4-6個數字結尾的字符串
console.log(reg.test('1xiaozhima666')) // false
console.log(reg.test('22werwf2e3rgdfg'))// false
console.log(reg.test('432aefasdfsdfsf3456'))// true
console.log(reg.test('3453245254')) // true 


// 正則中有 ^ $ 他就是說字符串必須所有知足正則
// 正則中沒有 ^ $ 只要字符串中有符合這個正則的字符便可 
// var reg2 = /\d/;
var reg = /^\d$/; // 以數字開頭 以數字結尾:以一個數字開頭 還得以這個數字結尾
console.log(reg.test('432aefasdfsdfsf3456'))// false
console.log(reg.test('3453245254')) // false
console.log(reg.test('3333')) // false
console.log(reg.test('1')) // true
console.log(reg.test('9'))// true
console.log(reg.test('4'))// true
console.log(reg.test('5'))// true 
console.log(reg.test('8'))// true



var reg  = /^\d{2,3}$/;// 以兩到三個數字開頭 還得以這兩到三個數字結尾 
// 也就是說 這個正則只能匹配 兩到三位數字的字符串
console.log(reg.test('432aefasdfsdfsf3456'))// false
console.log(reg.test('3453245254')) // false
console.log(reg.test('3333')) // false
console.log(reg.test('1')) // false
console.log(reg.test('9'))// false
console.log(reg.test('4'))// false
console.log(reg.test('5'))// false
console.log(reg.test('8'))// false
console.log(reg.test('18'))// true 



var reg = /^\d+.\d{2}$/;
console.log(reg.test('123.345'))// false
console.log(reg.test('123r34')) // true
console.log(reg.test('1235345'))//true
console.log(reg.test('123r345')) // false
console.log(reg.test('123 345')) // false
console.log(reg.test('123r45')) // true 



var reg = /\\d+/;// 要去匹配一個 \ 後邊是1到多個d字符 ‘\dd......’
console.log(reg.test('qqwewer'))// false
console.log(reg.test('134543'))// false
console.log(reg.test('134543d'))// false
console.log(reg.test('dd'))// false
console.log(reg.test('\dd'))// true
console.log(reg.test('\\dd')) //true
複製代碼

中括號[ ]:或的相關練習

  • 中括號中出現的字符通常都表明自己的含義
    • [] 中的:量詞元字符 | . 再也不具備特殊含義了;
    • \d在中括號中仍是0-9
  • [] 中的字符 ‘-’ 是按照 對應的的阿斯克碼值對應的;
  • [] 中要是想讓 ‘-’ 表明他本身:建議最好放在末尾
    • 例如:/[\w@#?-]+/
  • 中括號中不存在多位數
var reg = /[a-c]/;// 就是 有abc中的任意一個字符 便可
console.log(reg.test('aeadfgergdfgd'))//true
console.log(reg.test('234werrfrb')) // true
console.log(reg.test('acaca')) // true
console.log(reg.test('bbbbb')) // true 


// [] 中的字符 ‘-’ 是按照 對應的的阿斯克碼值對應的
// var reg = /[c-a]/ ;是不能夠的會報錯
// var reg = /[C-a]/ ;// ASCII:67(大C)-97(小a) 
var reg = /[c\-a]/ ;// c 或者 ‘-’ 或者 a ;這裏的‘-’沒有意義了,只是一個‘-’
var reg = /[.]/;// 在 [] 中的點 就表明 點兒自己 
//=>[] 中的:量詞元字符 | . 再也不具備特殊含義了;


var  reg = /^[1.2]$/;// 該正則 只能匹配一個字符; 1或.或2
console.log(reg.test('1.2'))//false;
console.log(reg.test('1q2'))//false
console.log(reg.test('1')) // true
console.log(reg.test('2'))// true
複製代碼

點的相關練習

var  reg = /^1.2$/;// 該正則 1開頭 2結尾 中間有一個任意字符
console.log(reg.test('1.2'))//;true
console.log(reg.test('1q2'))//true
console.log(reg.test('1')) // false
console.log(reg.test('2'))// false
複製代碼

轉義的相關練習

  • 正則中的轉義: 就是把 正則中 有特殊含義的字符 轉義字符自己
  • 字符串中的轉義: 就是把 字符串中 有特殊含義的字符 轉義成字符自己;
var  reg = /^1\.2$/;// 該正則 1開頭 2結尾 中間有一個點
console.log(reg.test('1.2'))//;true
console.log(reg.test('1q2'))//false
console.log(reg.test('1')) // false
console.log(reg.test('2'))// false */

// 轉義 一個是正則中的轉義 一個是字符串中的轉義
//正則中的轉義 就是把 正則中 有特殊含義的字符 轉義字符自己
//字符串中的轉義 就是把 字符串中 有特殊含義的字符 轉義成字符自己;' " \
複製代碼

豎|:或的相關練習

  • 直接x|y會存在很亂的優先級問題,通常咱們寫的時候都伴隨着小括號進行分組,由於小括號改變處理的優先級 =>小括號:分組
var reg = /18|19/;// 含有 18或者19便可
console.log(reg.test('18'))
console.log(reg.test('19'))
console.log(reg.test('189'))
console.log(reg.test('1819'))
console.log(reg.test('819'))
console.log(reg.test('1918'))
console.log(reg.test('118')) 


var reg = /^18|19/;// 18開頭的 或者 含有19的 就是true;
console.log(reg.test('18')) // true
console.log(reg.test('19')) // true
console.log(reg.test('189'))//true
console.log(reg.test('1819'))//true
console.log(reg.test('819'))//true
console.log(reg.test('1918'))//true
console.log(reg.test('118')) // false
console.log(reg.test('119')) // true 


var reg = /^18|19$/;// 18開頭的 或者 以19結尾的 就是true;
console.log(reg.test('18')) // true
console.log(reg.test('19')) // true
console.log(reg.test('189'))//true
console.log(reg.test('1819'))//true
console.log(reg.test('819'))//true
console.log(reg.test('1918'))//false
console.log(reg.test('118')) // false
console.log(reg.test('119')) // true


// 編寫一個正則 只有18 或者 19 匹配的結果是 true; 其餘都是false;
var reg = /^(18|19)$/;// 只能匹配18或者19
console.log(reg.test('18')) // true
console.log(reg.test('19')) // true
console.log(reg.test('189'))//false
console.log(reg.test('1819'))//false
console.log(reg.test('819'))//false
console.log(reg.test('1918'))//false
console.log(reg.test('118')) // false
console.log(reg.test('119')) // false


var reg = /^[18|19]$/;// 只能匹配 1 8 | 1 9 五個中的一位 
var reg = /^1[89]$/; // 以1開頭 後邊是 8或者9 結尾;
var reg = /^[18]9$/; // 以1或者8開頭 9結尾
var reg = /^1(8|9)$/;// 以1開頭 後邊是 8或者9 結尾;
複製代碼

四、應用練習

-1)、編寫一個正則 能夠匹配用戶輸入的手機號是否合法(寬泛)

規則:

  • 一、以1開頭
  • 二、11位數字
  • 三、第二位不能012
let rex = /^1[3-9]\d{9}$/
複製代碼

-2)、編寫一個正則 能夠匹配有效數字

規則:

  • 一、可能出現 + - 號,也可能不出現 : [+-]?
  • 二、一位0-9均可以,多位首位不能是0 :(\d|([1-9]\d+))
  • 三、小數部分可能有可能沒有,一旦有後面必須有小數點+數字: (.\d+)?
let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/;
複製代碼

-3)、編寫一個正則 能夠驗證真實姓名的

規則:

  • 一、漢字 : /^[\u4E00-\u9FA5]$/
  • 二、名字長度 2~10位
  • 三、可能有譯名 ·漢字 : (·[\u4E00-\u9FA5]{2,10}){0,2}
let reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/;
複製代碼

-4)、編寫一個正則 能夠匹配 18-65 之間的年齡

規則:

  • 一、整數
  • 18-19 ;20-59 : [2-5]\d ; 6[0-5]
let reg = /^(1[89]|[2-5]\d|6[0-5])$/;
複製代碼

-5)、編寫一個正則 能夠匹配郵箱

規則一:郵箱的名字由「數字、字母、下劃線、-、.」幾部分組成,可是-/.不能連續出現也不能做爲開始

  • 一、開頭是數字字母下劃線(1到多位)

  • 二、還能夠是 -數字字母下劃線 或者 .數字字母下劃線,總體零到屢次

    => \w+((-\w+)|(.\w+))*

規則二:

  • 一、@後面緊跟着:數字、字母 (1-多位)

    => @[A-Za-z0-9]+

  • 二、對@後面名字的補充

    • 多域名 .com.cn
    • 企業郵箱 xxx@xxxxxxxx-xxx-office.com

    => ((.|-)[A-Za-z0-9]+)*

  • 三、匹配最後的域名(.com/.cn/.org/.edu/.net...)

    => .[A-Za-z0-9]+

let reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
複製代碼

-6)、編寫一個正則 能夠匹配身份證號碼

規則:

  • 一、一共18位
  • 二、最後一位多是X
  • 三、身份證前六位:省市縣(第一位不能是0)
  • 四、出生的年 19 或 20 :((19|20)\d{2})
  • 五、月份 01-12 :(0[1-9]|1[0-2])
  • 六、日期 01-31 :(0[1-9]|[1-2]\d|3[01])
  • 七、最後一位 => X或者數字 :(\d|X)
  • 八、倒數第二位 => 偶數 女 奇數 男 :(\d{2}(\d))
let reg = /^[1-9]\d{5}((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[01])\d{3}(\d|X)$/i;
複製代碼

-7)、編寫一個正則 能夠匹配用戶輸入的密碼是否符合規則;

規則:

  • 一、8-18位
  • 二、既有大寫字母 又有小寫字母 還得有數字
function judge(str) {
    if (str.length < 8 || str.length > 18) return false
    if (!/[A-Z]/.test(str)) return false
    if (!/[a-z]/.test(str)) return false
    if (!/\d/.test(str)) return false
    return true;
  }

let reg = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,18}$/

//=> 必須有特殊字符時
let reg = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[#?&*-])[a-zA-Z0-9#?&*-]{8,18}$/

//=> 密碼是由8-18位的數字或者字母組成 不要求全部類型都存在
let reg = /^[0-9A-Za-z]{8,18}$/;
複製代碼

另外分享一個正則查找工具:菜鳥工具

3、正則的捕獲(exec)

編寫一個正則(制定了一套規則):去把某個字符串中符合這個規則的字符獲取到

一、語法

  • 正則.exec(字符串)

二、前提

實現正則捕獲的前提是:當前正則要和字符串匹配,若是不匹配捕獲的結果是null

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /^\d+$/;
console.log(reg.test(str)); //=>false
console.log(reg.exec(str)); //=>null
複製代碼

三、返回值

  • 找到了匹配的文本, 則返回一個數組
    • 數組中第一項:本次捕獲到的內容
    • 其他項:對應小分組本次單獨捕獲的內容
    • index:當前捕獲內容在字符串中的起始索引
    • input:原始字符串
    • ......
  • 找不到則不然返回null
let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.log(reg.exec(str));
複製代碼

四、捕獲的特色

-1)、懶惰性

每執行一次exec,只能捕獲到一個符合正則規則的,默認狀況下,咱們執行一百遍,獲取的結果永遠都是第一個匹配到的,其他的捕獲不到

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
複製代碼

懶惰性的解決辦法

想解決懶惰性,咱們首先要知道正則爲啥會有這個特性呢?

  • 那咱們先看下咱們寫的正則在控制檯輸出都有啥內容
let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.dir(reg);
複製代碼

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/;
console.log(reg.lastIndex); //=>0 下面匹配捕獲是從STR索引零的位置開始找
console.log(reg.exec(str));
console.log(reg.lastIndex); //=>0 第一次匹配捕獲完成,lastIndex沒有改變,因此下一次exec依然是從字符串最開始找,找到的永遠是第一個匹配到的
複製代碼

reg.lastIndex:當前正則下一次匹配的起始索引位置(那咱們就能夠知道正則懶惰的緣由了)

  • 懶惰性捕獲的緣由:默認狀況下lastIndex的值不會被修改,每一次都是從字符串開始位置查找,因此找到的永遠只是第一個

如今咱們知道了正則爲啥會這麼「懶」了,咱們就能夠「對症下藥」治一治他的懶惰性了😄

解決辦法:全局修飾符g

let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/g;
console.log(reg.exec(str)); //=>["2019"...]
console.log(reg.lastIndex); //=> 13 //=>設置全局匹配修飾符g後,第一次匹配完,lastIndex會本身修改
console.log(reg.exec(str)); //=>["2020"...]
console.log(reg.lastIndex); //=> 26
console.log(reg.exec(str)); //=>["2021"...]
console.log(reg.lastIndex); //=> 39
console.log(reg.exec(str)); //=>null 當所有捕獲後,再次捕獲的結果是null,可是lastIndex又迴歸了初始值零,再次捕獲又從第一個開始了... 
console.log(reg.lastIndex); //=>0
console.log(reg.exec(str)); //=>["2019"...]
複製代碼

上面咱們說過實現正則捕獲的前提是:當前正則要和字符串匹配,若是不匹配捕獲的結果是null

  • 那咱們驗證一下:正則和字符串匹配會不會影響lastIndex
let str = "xiaozhima2019xiaozhima2020xiaozhima2021";
let reg = /\d+/g;
if (reg.test(str)) {
    //=>驗證一下:只有正則和字符串匹配咱們在捕獲
    console.log(reg.lastIndex); //=>11 基於TEST匹配驗證後,LASTINDEX已經被修改成第一次匹配後的結果,因此下一次捕獲再也不從頭開始了
    console.log(reg.exec(str)); //=>["2020"...]
 }
複製代碼

需求練習:編寫一個方法execAll,執行一次能夠把全部匹配的結果捕獲到(前提正則必定要設置全局修飾符g)

~ function () {
    function execAll(str = "") {
        //=>str:要匹配的字符串
        //=>this:RegExp的實例(當前操做的正則)
        //=>進來後的第一件事,是驗證當前正則是否設置了G,不設置則不能在進行循環捕獲了,不然會致使死循環
        if (!this.global) return this.exec(str);
        //=>ARY存儲最後全部捕獲的信息 RES存儲每一次捕獲的內容(數組)
        let ary = [],
            res = this.exec(str);
        while (res) {
            //=>把每一次捕獲的內容RES[0]存放到數組中
            ary.push(res[0]);
            //=>只要捕獲的內容不爲NULL,則繼續捕獲下去
            res = this.exec(str);
        }
        return ary.length === 0 ? null : ary;
    }
    RegExp.prototype.execAll = execAll;
}();

let reg = /\d+/g;
console.log(reg.execAll("金色2019@2020小芝麻")); //=> ["2019", "2020"]
//=>字符串中的MATCH方法,能夠在執行一次的狀況下,捕獲到全部匹配的數據(前提:正則也得設置G才能夠)
console.log("金色2019@2020小芝麻".match(reg));//=> ["2019", "2020"]
複製代碼

-2)、貪婪性

默認狀況下,正則捕獲的時候,是按照當前正則所匹配的最長結果來獲取的

let str = "金色2019@2020小芝麻";
//=>正則捕獲的貪婪性:默認狀況下,正則捕獲的時候,是按照當前正則所匹配的最長結果來獲取的
let reg = /\d+/g;
console.log(reg.exec(str)); //=>["2019",......]
複製代碼

若是咱們如今的需求是隻想要一個「2」

貪婪性的解決辦法

在量詞元字符後面設置:取消捕獲時候的貪婪性(按照正則匹配的最短結果來獲取)

let str = "金色2019@2020小芝麻";
reg = /\d+?/g;
console.log(reg.exec(str)); //=>["2",......]
複製代碼

思惟導圖:正則匹配和捕獲

4、正則的其餘經常使用知識點

一、問號?在正則中的五大做用:

問號在正則中的五大做用:

  • 問號左邊是非量詞元字符:自己表明量詞元字符,出現零到一次
  • 問號左邊是量詞元字符:取消捕獲時候的貪婪性
  • (?:) 只匹配不捕獲
  • (?=) 正向預查(必須得包含什麼)
  • (?!) 負向預查(必須不能有什麼)

二、分組()的三大做用

-1)、小分組的第一個做用:提升優先級

需求:捕獲身份證號碼中的出生年月日及性別

//=>第一項:大正則匹配的結果
//=>其他項:每個小分組單獨匹配捕獲的結果
//=>若是設置了分組(改變優先級),可是捕獲的時候不須要單獨捕獲,能夠基於?:來處理
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <input type="text"/>
  <button>提交</button>
  <h5></h5>
</body>
</html>
<script> /* 點擊提交按鈕 h5標籤展現 這個出生日期和性別 */ let inp = document.querySelector('input'), btn = document.querySelector('button'), h5 = document.querySelector('h5'); btn.onclick = function(){ let val = inp.value; var reg = /^[1-9]\d{5}((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[01])\d{2}(\d)(\d|X)$/i; let ary = reg.exec(val); console.log(ary); if(ary){ // 輸入的是一個合法正則 let str = `這我的的出生日期是${ary[1]}${ary[3]}${ary[4]}日;性別是${ary[5]%2 ? '男' : '女'}`; h5.innerHTML = str; }else{ alert('不是一個合法的身份證號碼') } } </script>
複製代碼

-2)、小分組的第二個做用:分組捕獲

需求:既要捕獲到{數字},也想單獨的把數字也獲取到,例如:第一次找到 {0} 還須要單獨獲取0

//=>既要捕獲到{數字},也想單獨的把數字也獲取到,例如:第一次找到 {0} 還須要單獨獲取0
let str = "{0}年{1}月{2}日";

//=>不設置g只匹配一次,exec和match獲取的結果一致(既有大正則匹配的信息,也有小分組匹配的信息)
let reg = /\{(\d+)\}/;
console.log(reg.exec(str));
console.log(str.match(reg));
//["{0}", "0",...]

let reg = /\{(\d+)\}/g;
console.log(str.match(reg)); //=>["{0}", "{1}", "{2}"] 
//屢次匹配的狀況下,match只能把大正則匹配的內容獲取到,小分組匹配的信息沒法獲取


//=> 本身寫一個方法,完成需求
let aryBig=[],
    arySmall=[],
    res=reg.exec(str);
while(res){
    let [big,small]=res;
    aryBig.push(big);
    arySmall.push(small);
    res=reg.exec(str);
}
console.log(aryBig,arySmall); //=>["{0}", "{1}", "{2}"] ["0", "1", "2"]
複製代碼

-3)、 小分組的第三個做用:分組引用

分組引用就是經過「\數字」讓其表明和對應分組出現如出一轍的內容

//=>分組的第三個做用:「分組引用」
let str = "book"; //=>"good"、"look"、"moon"、"foot"...
let reg = /^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/; //=>分組引用就是經過「\數字」讓其表明和對應分組出現如出一轍的內容
console.log(reg.test("book")); //=>true
console.log(reg.test("deep")); //=>true
console.log(reg.test("some")); //=>false
複製代碼

三、正則捕獲的其餘方法及案例

-1)、test也能捕獲(本意是匹配)

  • RegExp.$&:是獲取當前大正則的內容
  • RegExp.$1~RegExp.$9:獲取當前本次正則匹配後,第一個到第九個分組的信息
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"0" 獲取當前本次匹配項中,第一個分組匹配的內容
   
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"1" 獲取當前本次匹配項中,第一個分組匹配的內容
   
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"2" 獲取當前本次匹配項中,第一個分組匹配的內容
   
console.log(reg.test(str)); //=>false
console.log(RegExp.$1); //=>"2" 存儲的是上次捕獲的結果
   
//=>RegExp.$1~RegExp.$9:獲取當前本次正則匹配後,第一個到第九個分組的信息
複製代碼

-2)、分組具名化(ES6新增)

至關於給分組起名字

  • 語法: ?<名字>
  • 後期匹配完,能夠基於匹配結果中的 groups 獲取制定名字分組捕獲的信息
reg = /^(?<A>\d{6})(?<B>\d{4})(?<C>\d{2})(?<D>\d{2})\d{2}(?<E>\d)(?:\d|X)$/;
let res = reg.exec(str);
console.log(res.groups.A);
console.log(res.groups.E); 
複製代碼

這裏咱們不在講解,推薦一篇阮一峯老師的ECMAScript 6 入門 裏面有詳細的講解,小芝麻就不在這裏班門弄斧了😄

-3)、字符串中和正則搭配的捕獲方法之—— match

咱們上面已經簡單的提過了,這裏主要說下matchesec的區別

matchesec的區別

  • 一、設置全局修飾符 g 的狀況下:
    • exec 每次執行只能捕獲一個匹配的結果
      • 當前結果中包含大正則和小分組匹配的結果
      • 若是想要捕獲全,須要執行屢次
    • match 執行一次就能把全部正則匹配的信息捕獲到
      • 只有大正則匹配的,並不包含小分組匹配的信息
  • 二、若是不設置 g 的狀況下:
    • 都只能捕獲到第一個匹配的結果,獲取的結果一摸同樣 (大正則,小分組都包含)

-4)、字符串中和正則搭配的捕獲方法之—— replace

自己是字符串替換的意思

  • 在不使用正則的狀況下,每一次執行 replace 只能替換一個,並且不少需求不使用正則是沒法解決的
let str = "xiaozhima@2019|xiaozhima@2020";
//=>把"xiaozhima"替換成"小芝麻"
//1.不用正則,執行一次只能替換一個
str = str.replace("xiaozhima","小芝麻").replace("xiaozhima","小芝麻");
console.log(str);

//2.使用正則會簡單一點
str = str.replace(/xiaozhima/g,"小芝麻");
console.log(str);
複製代碼
  • 把"jinse"替換爲"jinsexiaozhima"
let str = "jinse@2019|jinse@2020";
//=>把"jinse"替換爲"jinsexiaozhima"
str=str.replace("jinse","jinsexiaozhima").replace("jinse","jinsexiaozhima");
//"jinsexiaozhimaxiaozhima@2019|jinse@2020" 每一次替換都是從字符串第一個位置開始找的(相似於正則捕獲的懶惰性)
複製代碼

let str = "jinse@2019|jinse@2020";
//=>基於正則g能夠實現
str = str.replace(/jinse/g,"jinsexiaozhima");
複製代碼

結合正則:

  • 語法:str = str.replace(reg,function)
  • 特色:
    • 一、首先會拿 正則 和 字符串 去進行匹配捕獲,匹配捕獲一次,就會把函數執行一次
    • 二、而且會把每一次捕獲的結果(和esec捕獲的結果同樣)傳遞給函數
      • 因此能夠用剩餘運算符接收每一次正則匹配的結果
      • 結果的順序:[大正則匹配的、小分組匹配的、捕獲的起始索引、原始字符串......]
    • 三、函數中返回啥,就至關於把原始字符串中,大正則匹配的結果替換成啥

案例:把時間字符串進行處理

//=> 要求傳入實參格式任意:xx-xx xx:xx ;但索引對應爲: 0年 1月 2日 3時 4分 5秒
String.prototype.formatTime = function formatTime(template) {
	// 1.根據操做的時間字符串獲取年月日小時分鐘秒等信息
	let arr = this.match(/\d+/g).map(item => {
		return item.length < 2 ? '0' + item : item;
	});

	// 2.解析格式化的模板,找到對應的時間,替換模板中的內容
	template = template || '{0}年{1}月{2}日 {3}時{4}分{5}秒';
	return template.replace(/\{(\d+)\}/g, (_, group) => {
		return arr[group] || "00";
	});
};

let time = "2020-4-8 16:36:8";
time = time.formatTime('{0}年{1}月{2}日');
console.log(time); //=> 2020年04月08日
複製代碼

案例:單詞首字母大寫

let str = "good good study,day day up!";
let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g;
//=>函數被執行了六次,每一次都把正則匹配信息傳遞給函數
//=>每一次ARG:["good","g"] ["good","g"] ["study","s"]...
str = str.replace(reg,(...arg)=>{
    let [content,$1]=arg;
    $1=$1.toUpperCase();
    content=content.substring(1);
    return $1+content;
});
console.log(str); //=>"Good Good Study,Day Day Up!"
複製代碼

案例:處理URL參數

// 獲取URL中的傳參信息(可能也包含HASH值)
String.prototype.queryURLParams = function queryURLParams() {
	let obj = {};
	// 哈希值值的處理
	this.replace(/#([^?=#&]+)/g, (_, group) => obj['HASH'] = group);
	// 問號傳參信息的處理
	this.replace(/([^?#=&]+)=([^?#=&]+)/g, (_, group1, group2) => {
		obj[group1] = group2;
	});
	return obj;
};
let str = 'http://www.xxxxxxxxx.cn/?lx=1&from=weixin&name=xxx#video';
let obj = str.queryURLParams();
console.log(obj); //=> {HASH: "video", lx: "1", from: "weixin", name: "xxx"}
複製代碼

案例:實現千分符處理

String.prototype.millimeter = function millimeter() {
	return this.replace(/\d{1,3}(?=(\d{3})+$)/g, value => {
		return value + ',';
	});
};

let str = "2312345638";
str = str.millimeter();
console.log(str); //=>"2,312,345,638"
複製代碼

思惟導圖——正則其餘經常使用知識點

相關文章
相關標籤/搜索