# 正则应用(总结)

# 1. 常见业务举例

常见业务(用户名,密码强度等,这里不列举,一搜一大把。),也可以看我总结的《前端表单验证常用的正则表达式》

# 1.1 用户名正则

//用户名正则,4到16位(字母,数字,下划线,减号)
var uPattern = /^[a-zA-Z0-9_-]{4,16}$/;
//输出 true
console.log(uPattern.test("caibaojian"));
//密码的强度必须是包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间。

var reg = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[\da-zA-Z]{8,10}$/;

1
2
3
4
5
6
7
8

# 2. 正则分组

正则表达式是一个字符一个字符的去匹配,所以如果要匹配一个单词如is ,就是必须写/is/, 如果想要匹配is 出现3次,就只能写/isisis/, 我们想使用量词/is{3}/,但这只表示s出现3次,那怎么修改才能表示is 出现三次,把is 用括号括起来,/(is){3}/. 用括号把is括起来,就表示是它是一个整体,一个组,它们要一起出现,才算匹配成功,所以称之为分组。分组有一个重要的概念,就是引用,当正则表达式中有分组时,我们可以获取到分组的内容,怎么获取,就是$n, n表示数字,$1 表示第一个分组的内容,$2 表示第二个分组的内容,$3 表示第三个分组的内容,依次类推,其实这里还有一个$0, 它比较特殊,所以单列出来,它表示,整个正则表达式匹配成功的内容

# 2.1 例子(如电话号码中间隐藏)

// 例子1
var reg=/(\d{3})\d{4}(\d{4})/;
var phone="13423874592";
console.log( phone.replace(reg,("$1****$2")));//134****4592

// 例子2:驼峰变中划线
'fooBarBaz'.replace(/([A-Z])/g,"-$1").toLowerCase() // foo-bar-baz

// 例子3
let reg = /(\d{4})-(\d{2})-(\d{2})/g;
let string = '2017-03-20'
let replaceString = string.replace(reg,"$2/$3/$1");
console.log(replaceString)  //  03/20/2017

// 例子4
let reg = /(\d)2\1/g;
let string = '121 222 323 424'
let replaceString = string.replace(reg,'X');
console.log(replaceString)  // X X X X
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3. 添加变量

// http://blog.csdn.net/icanlove/article/details/39499777
var v = "bl";

var re =new RegExp("^\\d+" + v + "quot;,"gim"); // re为/^\d+bl$/gim

//至此,最初的问题问题也完全解决了。

//另外,还有一种方法是用过eval动态执行一段字符串的方法,不过我觉得从各方面来说,都属下策。

var re = eval("/^\\d+" + v + "$/gim")
1
2
3
4
5
6
7
8
9
10

# 4. string的replace

查找符合正则的字符串,就替换成对应的字符串。返回替换后的内容

用法: String.replace(正则,新的字符串/回调函数)(在回调函数中,第一个参数指的是每次匹配成功的字符)

例子:敏感词过滤,比如 ”我爱北京天安门,天安门上太阳升“。------我爱*****,***上太阳升。即(北京和天安门变成号),

一开始我们可能会想到这样的方法:

var str = "我爱北京天安门,天安门上太阳升。";
var re = /北京|天安门/g; // 找到北京 或者天安门 全局匹配
var str2 = str.replace(re,'*');
alert(str2) //我爱**,*上太阳升
//这种只是把找到的变成了一个*,并不能几个字就对应几个*。
1
2
3
4
5

要想实现几个字对应几个*,我们可以用回调函数实现:

var str = "我爱北京天安门,天安门上太阳升。";
var re = /北京|天安门/g; // 找到北京 或者天安门 全局匹配
var str2 = str.replace(re,function(str){
console.log(str); //用来测试:函数的第一个参数代表每次搜索到的符合正则的字符,所以第一次str指的是北京 第二次str是天安门 第三次str是天安门
var result = '';
for(var i=0;i<str.length;i  ){
result  = '*';
}
return result; //所以搜索到了几个字就返回几个*
});
console.log(str2) //我爱*****,***上太阳升
1
2
3
4
5
6
7
8
9
10
11

整个过程就是,找到北京,替换成了两个*,找到天安门替换成了3个*,找到天安门替换成3个*。

var arr = {
    content: "你好#D12345#,hello#D321#world",
    lawitems: {
        "D12345": "aaaa",
        "D321": "bbbbb"
    }
}

arr.content = arr.content.replace(/#([^#]+)#/g, function (match, $1) {
    return arr.lawitems[$1]||match;//没有在lawitems找到返回原字符串
})
// "你好aaaa,hellobbbbbworld"
1
2
3
4
5
6
7
8
9
10
11
12

replace 是一个很有用的方法,经常会用到。

# 5. 边界类(boudary)

边界类主要用四个: ^ 表示以什么开始,$表示以什么结尾, boudary 表示单词边界,B 表示非单词边界。边界就是单词和单词相隔的地方,最明显的就是空格。

写一个例子来看一下可以更为直观。

let reg = /is/g;
let string = 'this is a dog '
let replaceString = string.replace(reg,"IS");
console.log(replaceString)  // thIS IS a dog
1
2
3
4

两个is 都被替换掉了,这符合预期。但我们怎么只替换中间的is,中间的is 有一个特点,它是一个单词,因为前面和后面都是空格,使得它与其它单词分开了,正因为有空格的存在is 才成为了一个单词,所以空格是单词边界, \b 可以匹配到它。把正则表达式改成 /\bis/g, 可以看到输出 this IS a dog, 只匹配第二个。 如果只想改变第一个呢?那好办,因为第一个is被包含在一个单词中,所以它的前面不是单词边界,直接改成B 就可以了, 正则表达式改成 /Bis/g 就可以了.

驼峰转中划线(-)

const hyphenateRE = /\B([A-Z])/g
const str = 'LiuWeiBo'
str.replace(hyphenateRE, '-$1').toLowerCase() // liu-wei-bo
1
2
3

# 6. 正则断言

断言,只匹配一个位置,比如看下方例子

// 比如,你想匹配一个“人”字,但是你只想匹配中国人的人字,不想匹配法国人的人就可以用一下表达式
/(?<=中国)/
// 所以,表达式与其他通配符连用才能起到效果。
/(?=.*[a-z])\d/
// 这个就表示  匹配以“任意字符连着一个小写字母”开头的数字,只匹配数字。
1
2
3
4
5
// 例子1
String(123456789).replace(/(\d)(?=(\d{3})+$)/g, "$1,");
// or
'123456789'.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
// 结果是:123,456,789

// 例子2:整数小数都兼容
'1234567890030.7890'.replace(/(?=\B(?:\d{3})+\b)(\d{3}(\.\d+$)?)/g,',$1');
1
2
3
4
5
6
7
8

# 6.1 (?=pattern) 正向先行断言

代表字符串中的一个位置,紧接该位置之后的字符序列能够匹配pattern

例如对a regular expression这个字符串,要想匹配regular中的re,但不能匹配expression中的re,可以用re(?=gular),该表达式限定了re右边的位置,这个位置之后是gular,但并不消耗gular这些字符,将表达式改为re(?=gular).,将会匹配reg,元字符.匹配了g,括号这一砣匹配了e和g之间的位置。

# 6.2 (?!pattern) 负向先行断言(负向预查,非获取匹配)

代表字符串中的一个位置,紧接该位置之后的字符序列不能匹配pattern

例如对regex represents regular expression这个字符串,要想匹配除regexregular之外的re,可以用re(?!g),该表达式限定了re右边的位置,这个位置后面不是字符g。负向和正向的区别,就在于该位置之后的字符能否匹配括号中的表达式。

// 不会匹配到含有 df的内容
var reg = /^(?!.*df).*$/     // df就是你不想匹配的一个字符串了。
reg.test('abc@c') // true

var str = `abc@c

abc@d

asdf@aa

asdfsdf@qq`

reg.test(str) // false
1
2
3
4
5
6
7
8
9
10
11
12
13

# 6.3 (?<=pattern) 正向后行断言

代表字符串中的一个位置,紧接该位置之前的字符序列能够匹配pattern ES6+支持后行断言

例如对regex represents regular expression这个字符串,有4个单词,要想匹配单词内部的re,但不匹配单词开头的re,可以用(?<=\w)re,单词内部的re,在re前面应该是一个单词字符。之所以叫后行断言,是因为正则表达式引擎在匹配字符串和表达式时,是从前向后逐个扫描字符串中的字符,并判断是否与表达式符合,当在表达式中遇到该断言时,正则表达式引擎需要往字符串前端检测已扫描过的字符,相对于扫描方向是向后的。

# 6.4 (?<!pattern) 负向后行断言

代表字符串中的一个位置,紧接该位置之前的字符序列不能匹配pattern。 ES6+支持后行断言

例如对regex represents regular expression这个字符串,要想匹配单词开头的re,可以用(?<!\w)re。单词开头的re,在本例中,也就是指不在单词内部的re,即re前面不是单词字符。当然也可以用\bre来匹配。

# 7. 多行匹配

^$ 很好理解, /^T/以大写字母T开头即可, /T$/ 以大写字母T结束即可, 要注意它们的书写位置,一个在前,一个在后. 如果字符串中有换行符, let string = '@123 @456 @789', 字符串表现地就像有三行一样. 以下是chrome 浏览器中的输出

这时如果以/^@/g 去进行匹配的话,它只会匹配第一个@,


let reg = /^@/g;
let string = `@123
@456
@789`
let replaceString = string.replace(reg,"X");
console.log(replaceString)
/*
*    X123
*    @456
*    @789
*/
1
2
3
4
5
6
7
8
9
10
11
12

如果想匹配三个,那就要用到m修饰符,多行标示符,它表示如果字符串中有换行符,那就把字符串当成多行看待。m 标示符,只有在正则表达式中有^或&时才起作用,这也是把m标示符放到这里说明的原因。