一、位置匹配攻略
1 如何匹配位置
1.1 开头和结尾 ^$
var result = "hello".replace(/^|$/g,"#");
undefined
console.log(result)
VM3394:1 #hello#
1.2 \b 和 \B
\b是单词边界,具体就是\w和\W之间的位置,
var result = "[JS] Lesson_01.mp4".replace(/\b/g,"#");
console.log(result)
VM3462:2 [#JS#] #Lesson_01#.#mp4#
\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
1.3 (?=p) 和 (?!p)
(?=p) p是一个子模式,也就是p前边的位置,或者说该位置后边的字符要匹配 p .
简单来说就是p前边的那个位置
(?!) 表示l字符前面的字符
除了p 其他字符前边的位置
var result = "hello".replace(/(?=l)/g,"#");
console.log(result);
he#l#lo
var result = "hello".replace(/(?!l)/g,"#");
console.log(result)
#h#ell#o#
2、位置的特性
把位置理解成一个空字符串可以试试
var result = /(?=he)^^he(?=\w)llo$\b\b$/.test("hello")
console.log(result)
true
3、相关案例
3.1 不匹配任何东西的正则
类似于:/.^/
3.2数字的千分位分隔符表示法
把12345678变成12,345,678
- 弄出最后一个逗号
var result = "12345678".replace(/(?=\d{3}$)/g,",");
console.log(result)
12345,678
- 弄出所有的逗号
var result = "12345678".replace(/(?=(\d{3})+$)/g,",");
console.log(result);
12,345,678
- 匹配其他的案例
var result = "123456789".replace(/(?=(\d{3})+$)/g,",");
undefined
console.log(result)
,123,456,789 这样有bug所以需要改进
var result = "123456789".replace(regex,",");
var result2 = "12345678".replace(regex,",");
console.log(result)
console.log(result2)
123,456,789
12,345,678
- 如果输入的数字是:12,345,678呢?
也就是要求匹配单词边界
后头的\b是为了后头连着单词边界,也就是从后往前找
前边的\B表示前边不能是单词边界也就是第一个不能是逗号
var result = "123456,789".replace(/(\B)(?=(\d{3})+\b)/g,",");
console.log(result)
123,456,789
3.3 金额格式化
var a = 1999;
var b = a.toFixed(2).replace(/\B(?=(\d{3})+\b)/,",").replace(/^/,"$$ ");
undefined
console.log(b)
VM4095:1 $ 1,999.00
toFixed是一个数字的函数,他返回了的是一个字符串,然后参数是小数的位数
3.4 验证密码的问题
要求:6-12 数字 大写字母 小写字母 至少包括两种字符
简化 不考虑至少包括两种字符这一条件
var regex = /^[0-9A-Za-z]{6,13} $/g
判断是不是包某种字符
(如果必须包含的是数字的话)
var regex = /(?=.*\d)^[1-9a-zA-Z]{6,12}$/
同时包含两种字符
var regex = /(?=.*\d)(?=.*[a-z])^[1-9a-zA-Z]{6,12}$/
-
解答
- 包含数字和小写字母
- 包含数字和大写字母
- 包含小写字母和大写字母
- 数字 小写 大写
var regex = /(?=.*\d)(?=.*[A-Z])|(?=.*\d)(?=.*[a-z])|(?=.*[A-Z])(?=.*[a-z])^[1-9a-zA-Z]{6,12}$/
二、括号的作用
1、 分组和分支结构
- 1.1 分组
要匹配连续出现的ab时候就需要 /(ab)+/ - 1.2 分支
(p1|p2)
2、分组引用
我们可以进行数据提取,以及更强大的替换操作
/(\d{4})-(\d{2})-(\d{2})/
括号相当于多了一个分组
正则引擎也是这么做的,匹配过程中,给每一个分组都开辟一个空间用来储存每一个分组匹配到的数据
2.1 提取数据
- 提取出年月日
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2014-21-12"
console.log(string.match(regex))
["2014-21-12", "2014", "21", "12", index: 0, input: "2014-21-12"]
match方法第一个元素是整体匹配的结果,然后是各个分组(括号里)匹配的内容,然后是匹配下标最后是输入文本
正则的时候里边是否有g,match返回的数组格式是不一样的
也可以使用正则实例对象的exec方法:
console.log(regex.exec(string))
(4) ["2014-21-12", "2014", "21", "12", index: 0, input: "2014-21-12"]
regex.exec(string)
(4) ["2014-21-12", "2014", "21", "12", index: 0, input: "2014-21-12"]
console.log(RegExp.$2)
21
但是取值的时候,只有第一个数有值
2.2 替换
把yyyy-mm-dd
格式,替换成mm/dd/yyyy
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2014-21-12";
var result = string.replace(regex,"$2/$3/$1");
console.log(result)
21/12/2014
另一种方法
var result = string.replace(regex,function(match,year,month,day){
return month+"/"+day+"/"+year;
})
console.log(result)
21/12/2014
2.3 反向引用
除了使用相应的api来分株,也可以在正则本身里引用分株,但是只能用之前出现的分组,也就是反向引用
写一个正则支持匹配下面的三种格式
2012-12-12
2012/12/12
2012.12.12
第一个方法:
var regex = \d{4}(-|\.|\/)\d{2}\(-|\.|\/)\d{2};
这样就匹配的2012/12-12这样的数据
如果前后分隔符一致怎么办,
反向引用就可以实现了
var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
这里的\1表示前边的那个括号里不管匹配上的是什么值 \1都匹配了同样的摸个具体的字符
2.3.1 括号嵌套?
以左括号为准
var regex = /^((\d)(\d(\d)))\1\2\3$/
var string = "123123123"
- \1 表示123
- \2 表示 第一个\d 1
- \3 (\d(\d)) 23
- \4 3
2.3.2 \10表示什么
分组10 还是 \1 0
var regex = /(1)(2)(3)(4)(5)(6)(7)(8)(9)(#) \10+/
var string = "123456789# ######################################"
console.log(regex.test(string))
如果需匹配\1 0的话,请使用(?:\1)0 或者 \1(?:0)
2.3.3 引用不存在的分组
如果没有\2那就么就匹配\2表示对2进行了转义
2.3.4 非捕获括号
只用原始的功能,不去引用他,也不再正反向引用,非捕获括号
(?:p)
2.4相关案例
- trim方法模拟
function trim(str){
return str.replace(/^\s+|\s+$/g,"")
}
匹配整个字符串,然后应用提取出相应的数据
function trim(str){
return str.replace(/^\s*(.*?)\s*$/g,"$1")
}
trim(" 1231 ")
"1231"
惰性匹配为了防止最后一个空格之前所有的空格也被匹配上
function trim(str){
return str.replace(/^\s*(.*)\s*$/g,"$1")
}
trim(" 12s adf 31 ")
"12s adf 31 "
- 将首字母大写
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
- 驼峰化
function camelize(str){
return str.replace(/[-_\s]+(.)?/g,function(match,c){
return c?c.toUpperCase():"";
})
}
console.log(camelize('-moz-transform'))
MozTransform
这里匹配上的是-m -t但是c的意思是括号中的匹配项
- 中划线
function dasherize(str){
return str.replace(/([A-Z])/g,'-$1').replace(/[-_\s]+/g,"-").toLowerCase();
}
console.log(dasherize("MozTransform"))
-moz-transform
- html转义和反转义
function escapeHTML(str){
var escapeCars = {
'<':'lt','>':'gt','"':'quot','&':'amp','\`':'#39',
}
return str.replace(new RegExp('['+Object.keys(escapeCars).join('')+']',"g"),function(match){
return "&"+escapeCars[match]+";";
});
}
console.log(escapeHTML("<div> balh blah blah</div>"))
<div> balh blah blah</div>
- 匹配成对标签
三 回溯法原理
1 没有回溯的匹配
/ab{1,3}c/
目标是abbbc的时候就每一偶回溯,
2 有回溯的匹配
如果是abbc的时候就有问题了
3 常见的形式
本质上就是深度优先搜索算法,退到之前某一步的过程,我们称之为回朔
js会产生回朔的地方有哪些?
-
贪婪量词
- console.log("12345".match(/(\d{1,3})([\d]{1,3})/));123 45前边的先下手抢了三个
-
惰性量词
- 在贪婪次后头追加一个问号
- console.log("12345".match(/^(\d{1,3}?)([\d]{1,3})$/));
- (3) ["12345", "12", "345", index: 0, input: "12345"]
- 为了让后边的能够匹配上,不得不给前边多匹配一个数字
分支结构
-/candy|can/ 匹配can的时候前边就进行了部分匹配,后来发现candy匹配不就去第二个分支
四 正则表达式的拆分
1、结构和操作符
js正则表达式的结构:
- 字符字面变量 具体字符,需要和不需要转义的 a 和,
- 字符组 匹配一个字符,可以是多种可能之一[0-9] \d [^0-9] \D
- 量词 表示一个字符连续出现,a{1,3} +
- 锚 匹配一个位置而不是字符 \b (?=\d)
- 分组 括号表示一个整体,比如(ab)+ 也可以用非捕获分组(?:ab)
- 选择分支 sbv|qwe
操作符的优先级:
\转义字符
括号和方括号()、(?:...)(?=) (?!) []
量词和限定符 {} {m,n}{m,} ? * +
位置和序列 ^ $
管道符 |
/ab?(c|de)+|fg/
(c|d)是一个整体结构
c是整体 de另一个
然后
ab?(c|de)+ 和fg
2 注意点
2.1 匹配字符串整体的问题
要匹配整个字符串,我们经常会在正则前后加上锚^$
位置的优先级高于|所以
abc或者是bcd的时候^abc|bcd$不对的
要加括号
/(abc|bcd)/
2.2 元字符转义问题
^、$、。、*、 、+、?、|、\、/、(、)、[、]、{、}、=、!、:、-、
var a = "!@#$%^&*()"
var b = "\!\@\#\$\%\^\&\*\(\)"
console.log(a==b)
true
2.3 [] 和{}的问题
var var string = "[abcd]"
var regex = /\[abcd]/g
console.log(string.match(regex)[0])
[abcd]
1 正则表达式的四种操作
1.1、验证
表单验证什么的,
匹配的本质就是查找,有没有匹配,是不是匹配上判断是否的操作就是验证。
判断一个字符串是否有数字?
var regex = /\d/;
var string = "abc123";
console.log(!!~string.search(regex));
test match search exec
1.2 切分
js中的 split
html,css,javascript按逗号来切分
var regex = /\D/;
var string = "html,css,javascript"
console.log(string.split(regex));
["html","css","javascript"]
1.3 提取
整体匹配上了,但是需要提取部分匹配的数据,正则通常使用分组捕获的功能,需要相关API
var regex = /^(\d{4})\D(\d{2})\D(\d{2})$/
var string ="2014-12-12";
console.log(string.match(regex));
match (4) ["2014-12-12", "2014", "12", "12", index: 0, input: "2014-12-12"]
exec (4) ["2014-12-12", "2014", "12", "12", index: 0, input: "2014-12-12"]
test console.log(RegExp.$1,RegExp.$2,RegExp.$3) "2014", "12", "12"
search console.log(RegExp.$1,RegExp.$2,RegExp.$3) "2014", "12", "12"
replace **这个需要重点掌握**
2.相关api注意要点
String :
- search
- split
- match
- replace
RegExp:
- test
- exec
2.1 search match参数问题
这俩会把字符串转化为正则,
就是如果search(".")
需要修改为下列形式之一:
search("\.")
search(/./)
match也一样
match返回结果的格式问题
var string = "2014.12.12";
var regex1 = /\b(\d+)\b/;
var regex2 = /\b(\d+)\b/g;
console.log(string.match(regex1))
console.log(string.match(regex2))
(2) ["2014", "2014", index: 0, input: "2014.12.12"]
(3) ["2014", "12", "12"]
没有g的时候,返回的是标准匹配格式,也就是数组的第一个元素师整体匹配的内容,接下来是分株捕获的内容,然后是整体匹配第一个下标,最后是输入的目标字符串
有g 返回的是所有匹配的内容
使用字符串保存数据
一般情况我们都使用数组来保存数据,但看到有的框架中使用的是字符串,使用时,把字符串分切成数组,不一定用正则,分享下
var utils = {};
"Boolean |Nunber| Struing |Function |Array |Date |RegExp|Object|Error".split("|").forEach(
function(item){
utils["is"+item] = function(obj){
return {}.toString.call(obk) == "[object"+item+"]";
}
}
)
console.log(utils.isArray([1,2,3]))
console.log({}.toString.call([1,2,3]))
[object Array]
查询字符串压缩为例子
function compress (source){
var keys = {};
source.replace(/([^=&]+)=([^&]*)/g,function(full,key,value){
keys[key] = (keys[key]?keys[key]+",":"")+value;
})
var result = [];
for(var key in keys ){
result.push(key+"="+keys[key]);
}
return result.join("&")
}
console.log(compress("a=1&b=2&a=3&b=4"));
a=1,3&b=2,4