正規表達式
正規表達式(簡寫為 regexp) 用正則制定的規則,對字元串進行處理。如(查找 替換 比對某個字元串是否符合規則等)。在 JS 中主要用正規表達式來處理字元串。
程式設計中的日常應用:
表單驗證(驗證使用者填入的資訊 郵箱、使用者名、密碼格式是否合法)
日期格式化(2019-01-02 => 2019/01/02)
查找比對的關鍵詞('hello2018 hello2019' => [2018, 2019])
對文本内容進行比對替換
掌握了正規表達式,可能為你帶來超乎想象的文本處理能力。有時隻是一個簡單的指令,就可以幫你處理所有文本資料。
其實像我們的文本編輯器、IDE 都支援使用正則查找關鍵詞。
正規表達式文法
字面量方式
// 在兩個斜杠之間的字元内容稱為元字元 /元字元/
const reg = /\d/igm // \d是元字元代表[0-9]任意一位數 igm是修飾符
執行個體化方式
// 執行個體化方式邊界不需要加斜杠 對于特殊元字元需要加上轉義斜杠
const reg = new RegExp('\\d', 'igm')
// 可以拼接變量
const cn = 'china'
const reg1 = new RegExp(`${cn}\\d+`)
console.log(reg1) // /china\d+/
正規表達式中的元字元和修飾符
每一個正規表達式都是由元字元和修飾符組成的
// \d是特殊元字元 代表[0-9]中任意一個數字 igm是修飾符
const reg1 = /\d/igm
// 執行個體化方式邊界不需要加斜杠 對于特殊元字元前面需要加上轉義斜杠
const reg = new RegExp('\\d', 'igm')
正則比對
在 RegExp 原型有一個 test 方法,用來驗證字元内容是否符合正則。定義的每個正則都是 RegExp 類的執行個體。
文法:
reg.test('字元内容')
const reg = /\d/
reg.test('1') // true
修飾符
i ignoreCase 忽略大小寫
g global 全局比對
m multiline 多行比對
特殊元字元
在正則中具有特殊意義的字元
轉義字元
d 比對 0-9 的數字 包含 0 和 9 相當于[0-9]
D 除了 0-9 的任意字元
w 比對數字、字母、下劃線 相當于[0-9a-zA-Z_]
W 比對除了數字、字母、下劃線以外的其他字元,相當于
1s 比對空白符(空格s 換行rn 制表符 tab)
S 比對除了空白符(空格 換行 制表符)以外的字元
b 比對單詞邊界 'hello world'
n 比對換行符
^ 比對字元串的開始位置(以某個元字元作為開頭)
$ 比對字元串的結束位置(以某個元字元作為結尾)
. 比對除了n 以外的任意字元(在這裡預設不是小數點的意思 可以轉義為小數點 .)
console.log(/./.test('\n')) // false
console.log(/./.test('1')) // true
console.log(/./.test('w')) // true
console.log(/./.test('_')) // true
console.log(/./.test('.')) // true
// \. 轉義為普通小數點
console.log(/\./.test('.')) // true
console.log(/\./.test('1')) // false
console.log(/\./.test('w')) // false
其他元字元
x|y x 或者 y
[xyz] 比對 xyz 中的任意一個字元
2比對除了 xyz 以外的任意一個字元
[a-z] 比對 a 到 z 中的任意一個字元 [0-9] === d
3比對除了 a 到 z 以外的任意一個字元
4=== D
() 分組捕獲 括号中的内容單獨捕獲一次
(? 隻比對不捕獲
(?=) 正向預查
(?!) 負向預查
量詞元字元
? 出現 0 次或 1 一次(最多出現一次 可有可無)
- 代表出現 0 到多次,相當于{0,}
- 代表出現 1 到多次(至少出現一次),相當于{1,}
{n} 連續出現 n 次
{n,} 連續出現 n 到多次
{n,m} 連續出現 n 都 m 次(最少 n 次 最多 m 次)
普通元字元
/abc/
// 正則:由元字元和修飾符組成 處理字元串 比對驗證 捕獲 的規則
// RegExp
// 元字元:/\dasc/ 兩個斜杠之間的就是元字元 特殊元字元 量詞元字元 普通元字元
// 修飾符 /sdfds/igm
// 1.特殊元字元
// \ 轉義符 轉換為本來意義
// . 任意字元 除了\n(換行符) /./ /\./
// \n 比對換行符
// \d 0-9之間的一個數字 /\d/ [0-9]
// \D 除了\d 除的了0-9數字以外 /\D/ [^0-9]
// \b 比對邊界 '123 a12' /\b\d/ /\d\b/
// \B 非邊界 '123 a12' /\B\d/比對的是不以數字作為開頭的邊界 /\d\B/
// \w 數字0-9字母a-z A-Z下劃線_ 等價于 [0-9a-zA-Z_]
// \W 除了\w 除了數字0-9字母a-z A-Z下劃線_以外的字元
// \s 空格符
// \S 非空格
// [xyz] x或者y或者z 中的一個 '1x2y'
// [^xyz] 除了x或者y或者z中的 其他字元 'x123'
// [a-z] 比對a-z中任意一個小寫字母 'a'
// [^a-z] 除了a-z中任意一個字元
// x|y|z x或者y或者z
// () 分組 改變優先級 劃分小正則 分組引用
// ^ 以什麼開頭 /^\d/ '12' '1a'
// $ 以什麼結尾 /\d$/ 'a2'
// ?: 隻比對不捕獲
// ?= 正向預查
// ?! 負向預查
// 2.量詞元字元
// ? 出現0到1次(可有可無) /a?/ '1a23'
// * 出現0到多次 /a*/ '12aaaaaaaa312'
// + 出現1到多次 至少出現1次 /a+/ '123aaaaa12'
// {n} 限定出現n次 比對隻能出現n次 /a{2}/ '1aa1'
// {n,} 限定出現n到多次 至少出現n次 /a{2,}/ '1aaaaaa1'
// {n,m} 限定出現n到m次 /a{2, 5}/ '113aaa5' 出現2-5次 2 3 4 5
// 3.普通元字元
/abcd/
// 修飾符
// i ignoreCase 忽略大小寫 /[a-z]/i 'a' 'A'
// g global 全局 /[a-z]/g 's'
// m multiline 逐行比對 /^\d/ '123123'
正則中括号
/**
* [18] 不識别多位數 1 或者 8
* [12-68] 1或者 [2-6] 或者8
* [] 中括号裡 部分元字元代表本意 [.] [?] [+] [*]
* [\d] [\s] [\w] 代表是還是原本特殊的意義
*/
[]中不識别多位數
// [18] 不識别多位數 1 或者 8
let reg = /^[18]$/
console.log(reg.test('1')) // true
console.log(reg.test('8')) // true
console.log(reg.test('a')) // false
[12-68] 1 或者 [2-6] 或者 8
let reg = /^[12-68]$/
console.log(reg.test('1')) // true
console.log(reg.test('2')) // true
console.log(reg.test('6')) // true
console.log(reg.test('8')) // true
console.log(reg.test('9')) // false
[] 中括号裡部分元字元 代表普通元字元
// [\d] [\s] [\w] 代表是還是原本的特殊意義
// [\d] [0-9]
let reg = /[\d]/
reg.test('1') // true
// 代表普通元字元 [.] [?] [+] [*]
let reg = /[\w]/
console.log(reg.test('1'))
let reg = /[*]/
console.log(reg.test('*')) // true
let reg = /[+]/
console.log(reg.test('+')) // true
let reg = /[\d]/
console.log(reg.test('2')) // true
正則比對和捕獲
比對:驗證字元内容是否符合正則規則 傳回 true 或 false
捕獲: 将比對(符合正則規則)的内容 作為傳回值傳回給我們
RegExp 原型上的兩個方法
// test 檢測字元串内容是否符合(比對)正則規則。傳回值: boolean值
RegExp.prototype.test('字元内容')
// exec 将比對的内容,捕獲出來傳回給我們。傳回值:null或數組形式
RegExp.prototype.exec('字元内容')
test
/\d/.test('1') // true
exec
reg.exec('字元内容')
/**
["1", index: 0, input: "123", groups: undefined]
1.數組中從第一項開始時 是正則捕獲到的内容,如果有分組繼續往後排
2.index 正則捕獲内容的起始索引位置
3.input 原始字元串
4.groups 捕獲命名分組内容
*/
// ["1", index: 0, input: "123", groups: undefined]
/\d/.exec('123')
關于[]細節問題
// /[81]/ 不能識别多位數 看作是8或者1
// [a-z] a到z 26個小寫字母
// [13-56] 1 或者 3到5 或者6
// []中括号裡部分元字元代表的是本身意義 [+] '+' [?] '?' [.] '.'
// [\d] 依然代表的是 0-9中的一個數字
正則的一些簡單應用
驗證手機号
// 2. 手機号 188 176 138 11位數 開頭隻能是1
var reg = /^1(88|76|38)\d{8}$/; // ^$隻能是11位數 不能有其他字元
reg.test('17645678999')
reg.test('18845678999')
reg.test('13845678999')
驗證有效數字
let reg = /^[+-]?(\d|[1-9]\d)(\.\d+)?$/
console.log(reg.test('1'))
console.log(reg.test('-21'))
console.log(reg.test('1.1'))
console.log(reg.test('0'))
比對某個範圍内的數字
// 28-66
let reg = /^(2[89]|[2-5]\d|6[0-6])$/
console.log(reg.test('17'))
console.log(reg.test('18'))
console.log(reg.test('38'))
console.log(reg.test('65'))
console.log(reg.test('66'))
中文姓名
let reg = /^[\u4E00-\u9FA5]{2,10}$/
console.log(reg.test('adfs'))
console.log(reg.test('實體'))
驗證郵箱
// 雅虎郵箱 [email protected]
// 雅虎郵箱 [email protected]
// Google [email protected]
// QQ [email protected]
// [email protected]
// [email protected]
// [email protected]
let reg = /^[a-zA-Z0-9\u4E00-\u9FA5]+[a-zA-Z0-9\u4E00-\u9FA5_-]*@[a-zA-Z0-9_]+(\.[a-zA-Z0-9]+){1,2}$/
console.log(reg.test('[email protected]'))
console.log(reg.test('[email protected]'))
console.log(reg.test('愛麗絲[email protected]'))
console.log(reg.test('[email protected]'))
console.log(reg.test('[email protected]')) // false
console.log(reg.test('wenli-china@gmail')) // false
資料類型檢測
// "[Object xxx]"
let reg = /\[Object (\w+)\]/
console.log(reg.exec('[object Array]')[1])
// 資料類型檢測
Object.isType = function (val) {
let reg = /^\[object (\w+)\]$/
let res = Object.prototype.toString.call(val)
return reg.exec(res)[1].toLowerCase()
}
console.log(Object.isType(1))
console.log(Object.isType(null))
密碼驗證
// 包含 數字 字母大小寫
// let reg = /^(?!([a-zA-Z]+|\d+)$)[a-zA-Z\d]{8,15}$/
let reg = /^(?!([a-zA-Z]+|[a-z\d]+|[A-Z\d]+)$)[a-zA-Z\d]{8,15}$/
console.log(reg.test('lolABC123'))
正則屬性
/**
* 正則執行個體屬性
* flags: 目前正則的修飾符
* global: 是否有g修飾符(是否全局比對)true 有 false 無
* ignoreCase: 是否有i修飾符 (是否忽略大小寫) true 有 false 無
* multiline: 是否有m修飾符 (是否逐行比對) true 有 false 無
* source: 正則的元字元内容
*/
分組
1.分組捕獲
// 1.分組捕獲 将大正則劃分為小正則 對大正則捕獲到的内容進一步進行捕獲 放到數組裡
var str = '{10}11';
var reg = /\{(\d+)\}/;
console.log(reg.exec(str)); // ["{10}", "10", index: 0, input: "{10}11"]
2.改變優先級
// 2.改變優先級
var reg = /^10|20$/;
console.log(reg.test('10adf'));
console.log(reg.test('adf20'));
console.log(reg.test('10adf20'));
var reg = /^(10|20)$/; // 限定了 隻能是10或者20中的一個
console.log(reg.test('10'));
console.log(reg.test('20'));
3.分組引用
// 3.分組引用 (確定分組已經存在 在擷取分組引用 否則分組引用操作被忽略)
var reg = /([a-z])([a-z])\1\2/; // 'abab'
var reg = /([a-z])([a-z])\2\1/; // 'abba'
var reg = /([a-z])\1([a-z])\2/; // 'aabb'
var reg = /([a-z])\1([a-z])\2/; // 'aabb'
var reg = /\1(\d)/; // \1要是再第一個分組前面使用 會被忽略掉
console.log(reg.exec('1'));
var reg = /([a-z])\1([a-z])\2/; // 'aabb'
console.log(reg.test('aacc'));
console.log(reg.test('ddff'));
問号
/**
* ?
* 1.量詞元字元出現0到1次
* 2.?: 取消分組捕獲 隻比對不捕獲
* 3.?放在量詞元字元後面取消貪婪性 取消貪婪性 就按最短比對
* 4.?= 正向預查 一個條件 把條件寫在分組(?=1) 不會對它進行分組捕獲
* 5.?! 反向預查 一個條件 把條件寫在分組(?!1) 不會對它進行分組捕獲
*/
取消貪婪性
// 貪婪性 按照最長比對 能多比對就多比對
var str = 'h12345243';
// var reg = /\d+/; // + 等價于 {1,} 最短比對1 最長不限
// console.log(reg.exec(str));
// var reg = /\d{2,4}/; 按最長比對
// console.log(reg.exec(str)); // '1234'
// var reg = /\d{2,4}?/; // 取消貪婪性 就按最短比對
// console.log(reg.exec(str)); // '12'
取消分組捕獲
// 預設情況隻要你進行分組 捕獲的時候 都會進行分組捕獲
// ?: 取消分組捕獲 寫在分組的最前面 隻比對該分組 不會進行分組捕獲
var reg1 = /^[+-]?(?:\d|[1-9]\d+)(?:\.\d+)?$/g;
console.log(reg1.exec('-123.666'));
正向預查和負向預查
// 正向預查 限定條件
// var reg = /[a-z](?=3|4)/; // 捕獲的是字母後面跟着3或4的那個字母
// console.log(reg.exec('a3'));
// console.log(reg.exec('b4'));
// console.log(reg.exec('c3'));
// console.log(reg.exec('d6'));
// 反向預查 排除條件
// var reg = /[a-z](?!3|4)/; // 捕獲的是字母後面跟着不是3或4的那個字母
// console.log(reg.exec('a3'));
// console.log(reg.exec('b4'));
// console.log(reg.exec('c3'));
// console.log(reg.exec('d6'));
// var reg1 = /[a-z](?!3|4)/g;
// var str = 'a3b4c6h7';
// console.log(str.match(reg1));
// var reg = /^(?=3)\d$/; // 比對的一位數隻能是3
// console.log(reg.test('3'));
// console.log(reg.test('4'));
// console.log(reg.test('5'));
// var reg = /^((?=3)\d)+$/; // 出現的純數字 必須都是3
// console.log(reg.test('3'));
// console.log(reg.test('333333'));
// console.log(reg.test('34567'));
// console.log(reg.test('33345'));
// 比對沒有4的手機号
let reg = /^1((?!4)\d){10}$/
console.log(reg.test('15311199201'))
// var reg = /^(?!3)\d$/; // 比對的一位數不能是3
// console.log(reg.test('3')); // false
// console.log(reg.test('4')); // true
// console.log(reg.test('5')); // true
// var reg = /^((?!3)\d)+$/; // 出現的純數字 不能有3
// console.log(reg.test('3'));
// console.log(reg.test('4568'));
// console.log(reg.test('4567'));
// console.log(reg.test('33345'));
// var reg = /^(?!a)[a-z]$/; // 限定後面的範圍a-z 出現的一個字母不能是a
// console.log(reg.test('a'));
// console.log(reg.test('b'));
// console.log(reg.test('v'));
replace
交換字元串中的兩個單詞
var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newstr = str.replace(re, "$2, $1");
//"5=a,6=b,7=c"換成"a=5,b=6,c=7"
var str="5=a,6=b,7=c";
str=str.replace(/(\d+)=(\w)/g,"$2=$1");
console.log(str);
ES6 模闆字元串簡單實作
let name = 'wenli'
let country = 'china'
let str = `my name is ${name}, I like ${country}`
str = str.replace(/${(.*)}/, (a, b) => {
return eval(b)
})
console.log(str)
vue 模闆資料簡單實作
let data = {
title: 'hello zhufeng'
}
let str = '<h3>{{ title }}</h3>'
let reg = /{{(.*)}}/
str = str.replace(reg, function(a, b) {
return data[b.trim()]
})
console.log(str)
// console.log(document.body.innerHTML);
// console.log(oText.innerHTML);
// var mess = 'hello world!';
// var say = ' beijinghuanyingni';
// oText.innerHTML = oText.innerHTML.replace(/\{\{(.+?)\}\}/g, function (a, b) {
// console.log(arguments);
// return eval(b)
// });
// replace 支援正則
// var str = 'hh7h8';
// str = str.replace(/1/g, '2');
// str = str.replace(/\d/g, function (a) {
// console.log(arguments);
// // 第一個參數 比對到的内容
// // 第二個參數 捕獲到的索引位置
// // 第三個原始字元串
//// return 2 * arguments[0]
// console.log(a);
// return 2 * a
// });
// console.log(str);
// var str = '{01} -- {02} -- {03} -- {04}';
// var reg = /\{(\d)(\d)\}/g;
// str = str.replace(reg, function (a, b, c) { // 先把根據規則捕獲 然後再替換
//// console.log(arguments);
//// console.log(b);
//// 通過形參來得到捕獲到的内容
//
// // 第一項是大正則捕獲到内容
// // 從第二項開始是分組捕獲到的内容
// // 捕獲到的索引位置
// // 最後一個原始字元串
// return c + '' + b // 傳回值 替換大正則捕獲到的内容
// });
// console.log(str);
// str = str.replace(reg, '$2$1'); // $1第一個分組裡捕獲的内容$1-9
// console.log(str);
// var str = 'zhufeng123zhufeng666';
// var reg = /(\d+)/g;
//
// console.log(reg.exec(str)); // ["123", "123", index: 7, input: "zhufeng123zhufeng666"]
// console.log(reg.exec(str)); // ["666", "666", index: 17, input: "zhufeng123zhufeng666"]
// console.log(RegExp.$1); // 擷取到最近一次正則捕獲到的分組内容 $1-$9
// 2017-01-01 18:00:40 => 2017年01月01日 18時00分40秒
// 1.方式一
// var str = '2018-05-12 18:00:40';
// var reg = /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/;
// str = str.replace(reg, function (a, n1, n2, n3, n4, n5, n6) {
// console.log(arguments);
// return n1 + '年' + n2 + '月' + n3 + '日 ' + n4 + '時' + n5 + '分' + n6 + '秒'
// })
// console.log(str);
// str = str.replace(reg, '$1年$2月$3日 $4時$5分$6秒');
// console.log(str);
//
// 2. 方式二
// var time = ['年', '月', '日', '時', '分', '秒'];
// var n = 0; // 記錄索引
// var reg = /(\d+)[:-]?/g;
// var str = '2018-05-12 18:00:40';
// str = str.replace(reg, function (a, b) {
// // 2018- 2018
//// console.log(b + time[n++]); // 2018 + time[0] 2018年
// return b + time[n++];
// });
// console.log(str);
// 3.方式三
// var time = ['年', '月', '日', '時', '分', '秒'];
// var n = 0; // 記錄索引
// var str = '2018-05-12 18:00:40';
//// str.split(/[- :]/) // split 支援正則
//// console.log(str.split(/ /));
//// console.log(str.split(/\s/));
//
//// console.log(str.split(/[- :]/)); // ["2018", "05", "12", "18", "00", "40"]
// var arr = str.split(/[- :]/);
// str = str.replace(/\d+[-:]?/g, function () {
//// 2018- => arr[0]+''+time[0] 05- => arr[1]+ '' +time[1]
// var str2 = arr[n] + '' + time[n];
// n++;
// return str2;
// });
// console.log(str);
// 4.模闆引擎
// 2017-01-01 18:00:40 => 2017年01月01日 18時00分40秒
// var str = '2018-05-12 18:00:40';
// var tempStr = '{0}年{1}月{2}日 {3}時{4}分{5}秒'; // 模闆字元串
// var arr = str.split(/[: -]/); // ["2018", "05", "12", "18", "00", "40"]
// // console.log(arr);
// str = tempStr.replace(/\{(\d+)\}/g, function (a, b) {
// // arr[0] => {0} arr[1] => {1} arr[2] => {2}
// return arr[b];
// });
// console.log(str);
//
// var htmlStr = 'https://www.baidu.com/s?wd=123&id=28&name1=zhufeng';
//
// var htmlStr2 = 'https://www.baidu.com/s?wd=%E7%99%BE%E5%BA%A6&rsv_spt=1&rsv_iqid=0xb67cb0840000f3bc&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_enter=0&oq=vue&rsv_t=6babjh9kMd3aQtUraNwWM0bfzC5lnPlVkwqWVpOc2Ma898jqbZz9%2Byn76adAkylJ47pg&rsv_pq=ca645c620000ffb4';
// {wd: 123, id: 38, name: zhufeng}
// var reg = /([\w-]+)=([\w-]+)/g;
// var obj = {};
// htmlStr.replace(reg, function (a, b, c) {
//// console.log(arguments);
// obj[b] = c;
// });
// console.log(obj);
// var reg = /([^?&=]+)=([^?&=]+)/g;
// var obj = {};
// htmlStr.replace(reg, function () {
// obj[arguments[1]] = arguments[2];
// });
// console.log(obj);
//?wd=123&id=28&name1=zhufeng';
//var str3 = '?wd=123&id=28&name1=zhufeng';
// var reg = /[^?&]+/g;
//console.log(reg.exec(str3)); // "wd=123",
//console.log(reg.exec(str3)); // id=28
//console.log(reg.exec(str3)); // name1=zhufeng
//// 處理查詢字元串
// function getUrlParam(url) {
// var obj = {};
// var reg = /([^?&=]+)=([^?&=]+)/g;
// url.replace(reg, function () {
// obj[arguments[1]] = arguments[2]
// });
// return obj;
// }
//console.log(getUrlParam(htmlStr));
//console.log(getUrlParam(htmlStr2));
// 去除首尾空格
// var str = ' class1 class2 ';
// var reg = /^\s+|\s+$/g;
// var reg = /^ +| +$/g;
// str = str.replace(reg,'');
// console.log(str);
//console.log(str.trim());
// var str2 = str.trim(); // 自帶的去除首尾空格
// console.log(str2);
//
// String.prototype.myTrim = function () {
// var reg = /^\s+|\s+$/g;
// return this.replace(reg, '');
// };
//
// var str3 = str.myTrim();
// 千分符 2121345465 => 2,121,345,465
// 1
// var str = '2121345465';
//// console.log(str.split('').reverse().join('')); // 5645431212
// var str2 = str.split('').reverse().join(''); // 5645431212
//
// var reg = /(\d{3})/g;
//// str2 = str2.replace(reg, function () {
//// console.log(arguments);
//// return arguments[0] + ','
//// });
// str2 = str2.replace(reg, '$1,');
// console.log(str2.split('').reverse().join('')); // 2,121,345,465
// 2正向預查
var str = '2121345465.12'; // 2,121,345,465.12
var reg = /(\d)(?=(\d{3})+(\.\d+|$))/g;
// str = str.replace(reg, function () { // 三個數字為一組
//// console.log(arguments); // 2 121 345 465 三組
//// console.log(arguments); // 1 345 465 兩組
//// console.log(arguments); // 5 465 一組
// return arguments[0] + ',';
// });
// console.log(str);
str = str.replace(reg, '$1,');
console.log(str);
// 統計字元串中字母重複出現次數
let str = 'asdlfkj;;kajsd66sadff1233132'
str = Array.from(str).sort().join('')
let obj = {}
str.replace(/([a-zA-Z])\1*/g, a => {
obj[a[0]] = a.length
})
console.log(obj) // {a: 3, d: 3, f: 3, j: 2, k: 2, …}
// 每個單詞首字母大寫
let str = 'my name is brolly, hello world!'
let str2 = str.replace(/\b([a-zA-Z])/g, a => a.toUpperCase())
console.log(str2) // My Name Is Brolly, Hello World!
- 0-9a-za-z_ ↩
- xyz
- a-z
- 0-9