正则表达式是匹配模式,要么匹配字符,要么匹配位置。请记住这句话
(?=p) 就与 ^ 一样好理解,就是 p 前面的那个位置
单词边界的一个认识
\b 是单词边界,具体就是\w与\W之间的位置,也包括\w与 ^ 之间的位置,和\w与$之间的位置。
正则表达式,零宽断言.零宽断言的括号不会被纳入捕获中
"457347674837".replace(/(?=(...)+$)(?!^)/g, ',')
正预测:(?=expr) 断言某个位置的右边满足expr
负预测:(?!expr) 断言某个位置的右边 不 满足expr
'foo,bar,"abc,def",a,b,"x,y,z",baz,baa'.replace(/(?=([^"]*"[^"]*"[^"]*)*$|[^"]*$),/g,'|')
(/(?=([^"]*"[^"]*"[^"]*)*$|[^"]*$),/g,'|')
(/(?=([^"]*"[^"]*"[^"]*)*[^"]*$),/g,'|')
(/(?=([^"]*"[^"]*")*[^"]*$),/g,'|')
(/(?=(([^"]*"){2})*[^"]*$),/g,"|")
(?=(([^"]*"{2})*[^"]*$)
正常的括号不想被捕获到的时候,用(?:)
'foobar'.match(/o(b)/)
=>["ob", "b", index: 2, input: "foobar"]
'foobar'.match(/o(?:b)/)
=>["ob", index: 2, input: "foobar"]
new RegExp('')
=>/(?:)/
后向引用
/(expr)\1/ 其中\l表示前面(expr)捕获到的具体内容,以此类推:反/后向引用
^$ \b
'张三 张三三 李四 李四四 王五 王五五'.replace(/.(.)\1/g,"重叠的替换")
=>"张三 重叠的替换 李四 重叠的替换 王五 重叠的替换"
分组后面有量词的话,分组最终捕获到的数据是最后一次的匹配。
/(\d)+/.exec('12345')
(2) ["12345", "5", index: 0, input: "12345"]
此时得\1就是5
/(\d)+...\1/.test('12345 5')
/(\d)+...\1/.exec('123456 6')
(2) ["123456 6", "6", index: 0, input: "123456 6"]
可以用这种写法在js里模拟回顾型零宽断言
(?=expr1)(?:expr1)(?=expr2)
"barbazfoo".replace(/((?=bar)(?:bar)(?=ba))(b)/g,"啊")
=>"啊azfoo"
"barbazfoo".replace(/((?=bar)(?:bar)(?=ba))/g,"啊")
=>"啊bazfoo"
String.raw`xxxx`函数接收内容也是一个数组,因为可以插值 插值之后通过${}将字符串分割
function r(arg){
return arguments
}
rr`\\aa${5}\\bb${45}`
实质接收的参数:
arguments[0]: ["\aa", "\bb", "", raw: Array(3)]
raw:["\\aa", "\\bb", ""]
arguments[1]:5
2 :45
正则表达式中raw函数的实现
模板字符串在控制台打印出来是双引号
模板字符串 `aa{1}bb{2}cc{3}dd`
分成了四个部分 即:aa,bb,cc,dd
function raw(parts,...inserts){
return parts.raw.reduce((res,part,i)=>{
return res+inserts[i-1]+part
})
}
raw属性是一个数组,第0项是直接书写的内容
String.raw`xxxx`函数接收内容也是一个数组,因为可以插值 即上部分的函数表达式
`\\`不返回,因为系统会认为(\`)`
String.prototype.search2=function(re,startIndex){
re=new RegExp(re,'g')
re.lastIndex=startIndex
return re.exec(this)
}
new RegExp(String.raw` 内容 `)
要匹配'a' '-' 'z'符号
不能写成[a-z]
应该写成 [-az] [az-] [a\-z] 放在开头或者结尾 或者转义
\s 表示 [ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页
符。
表示匹配任意字符:可以使用 [\d\D]、[\w\W]、[\s\S] 和 [^] 中任何的一个。
|字符 分支结构也是惰性的
匹配时间 24小时制是四位数 00:00 每一位进行限定
/^([01][0-9])|[2][0-3]:[0-5]|[0-9]$/.
如果也要求匹配 "7:9",也就是说时分前面的 "0" 可以省略。
/^(0?[0-9]|1[0-9]|[2][0-3]):(0?[0-9]|[1-5][0-9])$/
匹配日期
/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]$)/
匹配文件夹
盘符:\文件夹\文件夹\文件夹\
/^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/
避免出现特殊符号
匹配id
/id=".*"/
/id="[^"]*"/
\m 用法
var result = "I\nlove\njavascript".replace(/^|$/gm, '#');
console.log(result);
/*
#I#
#love#
#javascript#
*/
/((?=.*[0-9])(?=.*[a-z])|(?=.*[0-9])(?=.*[A-Z])|(?=.*[a-z])(?=.*[AZ]))^[0-9A-Za-z]{6,12}$/
同时包含数字和小写字母
• 同时包含数字和大写字母
• 同时包含小写字母和大写字母
• 同时包含数字、小写字母和大写字母
• 以上的 4 种情况是或的关系(实际上,可以不用第 4 条)。
非贪婪模式为了整体匹配成,也会尽可能的贪婪的匹配 但是不会捕获(存在回溯现象)
正则表达式的优先级符号
一级:转义符
\
二级:括号和方括号
(...)(?:...)(?=...)(?!...)[...]
三级:量词限定符
{m}{mn}{m,}?*+
关于问号:
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
四级:位置和序列
^$ \元字符 一般字符
管道符:
|
所谓元字符,就是正则中有特殊含义的字符。
所有的元字符全部可以转义
一些练习题
1,将信用卡的前面的数字若干位变成###只留下后四位数字
function chage(cc){
return cc.replace(/.(?=....)/g,'#')
}
其他思路
function chage(cc){
return cc.slice(0,-4).replace(/./g,'#')+cc.slice(-4)
}
function chage(cc){
return cc.replace(/(?=.....)./g,'#')
}
2,前面第一个字母是编码,其单词的其他字母位置为反方向.
function reve(str){
return num.replace(/(\d+)(\w*)/g,(m,code,rest)=>{
return String.fromCharCode(+code)+rest.split('').reverse().join('')
})
}
eg:'72olle 103doo 100ya'
=> 'hello good day'
再把结果反转回去
function reveve(str){
return str.replace(/(\w)(\w*)/g,(_,first,rest)=>{
return first.charCodeAt(0)+rest.split('').reverse().join('')
})
}
3,前面第一个字母是编码,将第二个字符与最后一个字符互换了
function decipherThis(str) {
return str.replace(/\b(\d+)(\w)?(\w*?)(\w)?\b/g, (m, code, a,b,c) => {
return String.fromCharCode(+code) + (c||'') + (b||'') + (a||'')
})
};
4,删除所有单词右边的'!'
function x(str){
return str.replace(/(\w)(!*)(?= |$)/g,'$1')
}
eg:"Hi! Hi!".replace(/(\w)(!*)(?= |$)/g, '$1')
"Hi Hi"
其他思路
function remove(s){
return s.replace(/!*( |$)/g, '$1')
}
function remove(s){
return s.replace(/\b!+/g,'')
}
5,字符串是一个细胞,晚期的是C,初期的是c,常规细胞是小写字母,重要细胞是大写.
要求:重要细胞不能被剪掉,晚期的两边如果有不重要的一起砍掉,早期的砍掉
function cutCancerCells(str){
return str.replace(/c|[a-z]?C+[a-z]?/g,"")
}遇见小写的c或者大C的左边是单个小写[a-z]右边是[a-z] 非贪婪匹配.
特殊情况:'dhcCo'
"dh" 当删除c后下标会转移到C 开始从C匹配 忽略掉左[a-z]
6,给一个字符串,删除左右两侧给定的字符.
在原型上实现
c既是这个给定的字符
String.prototype.trim=function(c){
var re=/^c*|c*$/gi
if(c===undefined){
re = /^\s*|\s*$/gi
}else{
c=c.replace(/(?=[^\w\s])/g,'\\')
var re=new RegExp('^'+c+'*|'+c+'*$','gi')
}
return this.replace(re,'')
}
去空格 面试必备
function trim(str) {
return str.replace(/^\s+|\s+$/g, '');
}
function trim (str) {
return str.replace(/^\s*(.*?)\s*$/g, "$1");
}
将每个单词的首字母变成大写
function titleize (str) {
return str.toLowerCase().replace(/(?:^|\s)\w/g, function (c) {
return c.toUpperCase();
});
}
转驼峰
function camelize (str) {
return str.replace(/[-_\s]+(.)?/g, function (match, c) {
return c ? c.toUpperCase() : '';
});
}
console.log( camelize('-moz-transform') );