正则表达式
regular expression:RegExp
用来处理字符串的规则
- 只能处理字符串
- 它是一个规则:可以验证字符串是否符合某个规则(test),也可以把字符串中符合规则的内容捕获到(exec / match...)
正则表达式构造函数var reg=new RegExp(“xxx”)与正则表达字面量var reg=//有什么不同?
当使用RegExp()构造函数的时候,不仅需要转义引号(即\”表示”),并且还需要双反斜杠(即\\表示一个\)。使用正则表达字面量的效率更高
/*常用的元字符*/
//=>1.量词元字符:设置出现的次数
* 零到多次
+ 一到多次
? 零次或者一次
{n} 出现n次
{n,} 出现n到多次
{n,m} 出现n到m次
//=>2.特殊元字符:单个或者组合在一起代表特殊的含义
\ 转义字符(普通->特殊->普通)
. 除\n(换行符)以外的任意字符
^ 以哪一个元字符作为开始
$ 以哪一个元字符作为结束
\n 换行符
\d 0~9之间的一个数字
\D 非0~9之间的一个数字 (大写和小写的意思是相反的)
\w [0-9a-zA-Z_]
\W [^0-9a-zA-Z_]
\s 一个空白字符(包含空格、制表符、换页符等)[\t\v\n\r\f]
\S [^\t\v\n\r\f]
\t 一个制表符(一个TAB键:四个空格)
\b 匹配一个单词的边界
x|y x或者y中的一个字符
[xyz] x或者y或者z中的一个字符
[^xy] 除了x/y以外的任意字符
[a-z] 指定a-z这个范围中的任意字符 [0-9a-zA-Z_]===\w
[^a-z] 上一个的取反“非”
() 正则中的分组符号
(?:) 只匹配不捕获
(?=) 正向预查
(?!) 负向预查
//=>3.普通元字符:代表本身含义的
/zhufeng/ 此正则匹配的就是 "zhufeng"
/*正则表达式常用的修饰符:img*/
i =>ignoreCase 忽略单词大小写匹配
m =>multiline 可以进行多行匹配
g =>global 全局匹配
//=>^/$两个都不加:字符串中包含符合规则的内容即可
let reg1 = /\d+/;
//=>^/$两个都加:字符串只能是和规则一致的内容
let reg2 = /^\d+$/;
//=>举个例子:验证手机号码(11位,第一个数字是1即可)
let reg = /^1\d{10}$/;
/^2.3$/.test("2@3");//=>true
/^2.3$/.test("23");//=>false
/^2\.3$/.test("2.3");//=>true
/^\d$/; //=>\d代表0-9的数字
/^\\d$/.test("\\d"); //=>true
/^18|29$/;只匹配以18 和 29 为首的
/^(18|29)$/;//只能匹配18 和 29
/^[@+]$/.test("+"); //=>true 只匹配@ 和 +
/^[\d]$/.test("9");//=>true 只匹配0 ~ 9
/^[10-29]$/.test("10"));//=>false 只匹配1或者0-2或者9
常用的正则表达式
-
验证是否为有效数字
/* * 规则分析 * 1.可能出现 + - 号,也可能不出现 [+-]? * 2.一位0-9都可以,多位首位不能是0 (\d|([1-9]\d+)) * 3.小数部分可能有可能没有,一旦有后面必须有小数点+数字 (\.\d+)? */ let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/; -
验证真实姓名的
/* * 1.汉字 /^[\u4E00-\u9FA5]$/ * 2.名字长度 2~10位 * 3.可能有译名 ·汉字 (·[\u4E00-\u9FA5]{2,10}){0,2} */ let reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/; -
验证邮箱的
let reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/; //=> \w+((-\w+)|(\.\w+))* //1.开头是数字字母下划线(1到多位) //2.还可以是 -数字字母下划线 或者 .数字字母下划线,整体零到多次 //=>邮箱的名字由“数字、字母、下划线、-、.”几部分组成,但是-/.不能连续出现也不能作为开始 //=> @[A-Za-z0-9]+ //1.@后面紧跟着:数字、字母 (1-多位) //=> ((\.|-)[A-Za-z0-9]+)* //1.对@后面名字的补充 // 多域名 .com.cn // 企业邮箱 zxt@zhufeng-peixun-office.com //=> \.[A-Za-z0-9]+ //1. 这个匹配的是最后的域名(.com/.cn/.org/.edu/.net...) -
身份证号码
/* * 1. 一共18位 * 2. 最后一位可能是X * * 身份证前六位:省市县 130828 * 中间八位:年月日 * 最后四位: * 最后一位 => X或者数字 * 倒数第二位 => 偶数 女 奇数 男 * 其余的是经过算法算出来的 */ //let reg = /^\d{17}(\d|X)$/; //=>小括号分组的第二个作用:分组捕获,不仅可以把大正则匹配的信息捕获到,还可以单独捕获到每个小分组的内容 let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/; reg.exec("130828199012040617"); //=>["130828199012040617", "130828", "1990", "12", "04", "1", "7"...] 捕获结果是数组,包含每一个小分组单独获取的内容 -
正则两种创建方式的区别
//=> 构造函数因为传递的是字符串,\需要写两个才代表斜杠
let reg = /\d+/g;
reg = new RegExp("\\d+","g")
// => 正则表达是中的部分内容是变量存储的值
// 1.两个斜杠中间包起来的都是元字符(如果正则中要包含某个变量的值,则不会使用字面量方式创建)
let type = "zanlan";
/^@"+type+"@$/.test('@"""typeee"@');//=> true
let reg = new RegExp("^@"+type+"@$");
reg.test("@zanlan@");// => true
let str = "zhufeng2019yangfan2020qihang2021"
let reg = /\d+/;
console.log(reg.lastIndex);// 0
console.log(reg.exec(str));
console.log(reg.lastIndex);// 0
下一次exec依然是从字符串最开始找,找到的永远是第一个匹配到的
let reg = /\d+/g;
consolo.log(reg.exec(str)); ["2019"...]
console.log(reg.lastIndex); // 11 设置全局匹配后,第一次匹配完,lastIndex自动修改
consolo.log(reg.exec(str)); ["2020"...]
console.log(reg.lastIndex); // 22
consolo.log(reg.exec(str)); ["2021"...]
console.log(reg.lastIndex); // 32
consolo.log(reg.exec(str)); null,当全部捕获后,lastIndex重置为0
console.log(reg.lastIndex); // 0
consolo.log(reg.exec(str)); ["2019"...]
在一段字符串内,找到所有复合要求的字符串。
function execAll(str = ''){
if(!this.global) return this.exec(str);
let ary = [];
let res = this.exec(str);
while(res){
ary.push(res[0]);
res = this.exec(str);
}
return ary;
}
RegExp.prototype.execAll = execAll;
let reg = /\d+/g;
consolo.log(reg.execAll("zan2019@2020lan"));//["2019","2020"]
"zan2019@2020lan".match(reg);//["2019","2020"]
exec 和 match
let reg = /\{\d+\}/;
console.log(reg.exec(str));
console.log(str.match(reg));
//输出都为 ['{0}', '0', index: 0, input: '{0}年{1}月{2}日', groups: undefined]
let reg = /\{\d+\}/g;
console.log(str.match(reg));// ["0","1","2"]
\数字 让其代表和对应的分组出现一模一样的内容
let str = "book";
let reg = /^[a-z]([a-z])([A-Z])\2[a-z]$/;
console.log(reg.test("baAAa"))//true \2代表一个字符 跟序号为2的匹配一样
console.log(reg.test("baABa"))//false
贪婪匹配 和 惰性匹配
let str = 'zan2019@2020lan';
let reg1 = /\d+?/g
console.log(str.match(/\d+/g))//[ '2019', '2020' ] 贪婪
console.log(str.match(/\d+?/g))//['2','0','1','9', '2','0','2','0'] 惰性
'123 1234 12345 123456'.match(/\d{2,5}/g) // [ 123, 1234, 12345, 12345 ] 贪婪
'123 1234 12345 123456'.match(/\d{2,5}?/g) //[ 12, 12, 34, 12, 34, 12, 34, 56 ] 惰性
正向先行断言/正向预查 ?=p ,p代表是一个整体
console.log('xxx123456xxx'.replace(/(?=xxx)/g, '@')) // '@xxx123456@xxx'
负向先行断言 /负向预查 ?!p ,p代表是一个整体
'xxx123456'.replace(/(?!xxx)/g, '@') // 'x@x@x@1@2@3@4@5@6x@x@x@'
?<=p ,p代表是一个整体
console.log('xxx_love_study_1.mp4'.replace(/(?<=xxx)/g, '@')) // 'xxx@_love_study_1.mp4'
?<!p ,p代表是一个整体
console.log('xxx_love_study_1.mp4'.replace(/(?<!xxx)/g, '@'))
// 'x@x@x_@l@o@v@e@_@s@t@u@d@y@_@1@.@m@p@4@'
正向先行断言 ?=p ,p代表是一个整体
console.log('xxx123456xxx'.replace(/(?=xxx)/g, '@')) // '@xxx123456@xxx'
## 单词边界 \b
```javascript
\w和\W之间的位置
\w与^之间的位置
\w与$之间的位置
console.log('xxx_love_study_1.mp4'.replace(/\b/g, '@')) // '@xxx_love_study_1@.@mp4@'
非单词边界 \B
console.log('xxx_love_study_1.mp4'.replace(/\B/g, '@'))
// 'x@x@x@_@l@o@v@e@_@s@t@u@d@y@_@1.m@p@4'
实战
'123456789'.replace(/(?!^)(?=(\d{3})+$)/g, ',') // '123,456,789'
// 3的倍数个,且以它为结尾 的正向预查,且忽略匹配到的首位。
const formatMobile = (mobile) => {
// 12345678912
return String(mobile).slice(0, 11)
.replace(/(?<=\d{3})\d+/, function (...args) {
console.log(args) //[ '45678912', 3, '12345678912' ]
return '-' + args[0]
})
.replace(/(?<=[\d-]{8})\d{1,4}/, function (...args) {
console.log(args) //[ '8912', 8, '123-45678912' ]
return '-' + args[0]
})
}
console.log(formatMobile(12345678912))//123-4567-8912
console.log('<div id="container" class="main"></div>'.match(/id=".*?"/)[0])
console.log('<div id="container" class="main"></div>'.match(/id="[^"]*"/)[0])
// 都是输出'id="container"'
console.log("#ffbbad #Fc01DF #FFF #ffE".match(/#([a-fA-F\d]{6}|[a-fA-F\d]{3})/g))
//[ '#ffbbad', '#Fc01DF', '#FFF', '#ffE' ]
console.log(/^([01]\d|2[0-3]):[0-5]\d$/.test('23:59'))
// true
清除左右空格,两种方法都可以
const trim1 = (str) => {
return str.replace(/^\s*(.*?)\s*$/, '$1')
}
const trim2 = (str) => {
return str.replace(/^\s*|\s*$/g, '')
}
console.log('@' + trim1(' 123 ') +'@')
console.log('@' + trim2(' 123 ') +'@')
清除左右空格,两种方法都可以
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>zanlan</div>'));
//<div>zanlan</div>
正则表达式 用()括起来,匹配的内容用$1.....表示出来
var regex = /^(\d{4})-(\d{2})-(\d{2})$/;
var string = "2017-06-26";
regex.test(string);
console.log(RegExp.$1, RegExp.$2, RegExp.$3);
// "2017" "06" "26"
let str = "{0}年{1}月{2}日"
let reg = /\{(\d+)\}/g
console.log(reg.test(str))//true
console.log(RegExp.$1, RegExp.$2, RegExp.$3);//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
日期格式改写
var time = '2019-08-13'
var reg = /^(\d{4})-(\d{2})-(\d{2})$/
console.log(time.replace(reg, (str, $1, $2, $3) => {
console.log(str)// '2019-08-13'
return $1 + '年' + $2 + '月' + $3 + '日'
}))//'2019年08月13日'
console.log(time.replace(reg, '$1年$2月$3日'))// '2019年08月13日'
首字母大写
let str = 'good good study, day day up! '
let rege = /\b([a-zA-Z])[a-zA-Z]*\b/g
console.log(str.replace(rege, (s, $1) => {
return $1.toUpperCase() + s.slice(1)
}))
首字母大写
let str = 'good good study, day day up! '
let rege = /\b([a-zA-Z])[a-zA-Z]*\b/g
console.log(str.replace(rege, (s, $1) => {
return $1.toUpperCase() + s.slice(1)
}))
最长字符串1,弊端 只能检测到英文字母,其他字符长度失效
let str = 'zhufengpeixunzhoulaoshiAAA'
str = str.split('').sort((a, b) => a.localeCompare(b)).join('')
console.log(str)//aeefghhhiilnnoopsuuuxzz
let reg = /([a-zA-Z])\1*/g
let ary = str.match(reg)
console.log(ary)//['a','AAA','ee', 'hhh','ii', 'nn','oo', 'uuu','zz']
ary.sort((a, b) => b.length - a.length)
console.log(ary)// [ 'AAA','hhh', 'uuu','ee', 'ii','nn', 'oo','zz']
let max = ary[0].length
let res = [ary[0].substr(0, 1)]
for (let i = 1; i < ary.length; i++) {
let item = ary[i]
if (item.length < max) {
break
}
res.push(item.substr(0, 1))
}
console.log(res)//[ 'A','h', 'u' ]
最长字符串2
let str = 'zhufengpeixunzhoulaoshiAAAA----@@@@'
var max = 0
var res = []
var flag = false
str = str.split('').sort((a, b) => a.localeCompare(b)).join('')
console.log(str)//----@@@@aAAAAeefghhhiilnnoopsuuuxzz
for (var i = str.length; i > 0; i--) {
let reg = new RegExp("([a-zA-Z-@])\\1{" + (i - 1) + '}', "g")
str.replace(reg, (v, $1) => {
res.push($1)
max = i
flag = true
})
if (flag) break
}
console.log(res, max)// [ '-', '@', 'A' ] 4
日期格式转换
function formatTime(template = '{0}年{1}月{2}日 {3}时{4}分{5}秒'){
let timeAry = this.match(/\d+/g)
return template.replace(/\{(\d+)\}/g, (...[, $1]) => {
let time = timeAry[$1] || '00'
return time.length < 2 ? '0' + time : time
})
}
String.prototype.formatTime = formatTime
let time = '2019-8-13 16:51:3'
console.log(time.formatTime())//2019年08月13日 16时51分03秒
console.log(time.formatTime("{0}年{1}月{2}日"))//2019年08月13日
console.log(time.formatTime("{1}-{2} {3}:{4}"))//08-13 16:51
time = '2019-8-13'
console.log(time.formatTime())//2019年08月13日 00时00分00秒
console.log(time.formatTime("{0}年{1}月{2}日"))//2019年08月13日
console.log(time.formatTime("{1}-{2} {3}:{4}"))//08-13 00:00
解析url字符串为对象
function queryURLParams() {
let obj = {}
this.replace(/([^?=&#]+)=([^?=&#]+)/g, (...[, $1, $2]) => obj[$1] = $2)
this.replace(/#([^?=&#]+)/g, (...[, $1]) => obj.HASH = $1)
return obj
}
String.prototype.queryURLParams = queryURLParams
console.log('http://www.zanlan.cn/?name=zl&gender=男#video'.queryURLParams())
千分位符号
var reg = /\d{1,3}(?=(\d{3})+$)/g
console.log('1'.replace(reg, content => content + ','))//1
console.log('12'.replace(reg, content => content + ','))//12
console.log('123'.replace(reg, content => content + ','))//123
console.log('1234'.replace(reg, content => content + ','))//1,234
console.log('12345'.replace(reg, content => content + ','))//12,345
console.log('123456'.replace(reg, content => content + ','))//123,456
console.log('1234567'.replace(reg, content => content + ','))//1,234,567