正则表达式总结

Posted by jintang on 2014-07-20

编写正则表达式的基本思路:

  1. 在编写表达式时,应该先把正确的格式罗列,通过正确的格式来编写表达式
  2. 如果特殊的情况比较多,则考虑整体分为多个部分,部分解决

知识点:

  1. 在JS中,如果要引入正则表达式,需要使用 /…/
  2. 普通匹配符:能够匹配以之对应的字符
  3. 默认正则区分大小写
  4. match(/表达式/)匹配成功,返回数组,否则返回null
  5. i、g、m称为正则标记符(参数):i:不区分大小写 g:全局匹配 m:多行匹配
  6. 能够匹配多个字符中的其中一个匹配符:
    1. \d: 0-9
    2. \w: 字母、数字、下划线 ([a-zA-Z0-9_])
    3. .: 匹配除换行的所有字符(\d \w . 都是只能匹配一个字符)
  7. 能够自定义规则的匹配符 [],如果在[^]表示取反
  8. 用来修饰匹配次数的匹配符

    1. {n}: n次
    2. {n,m}: n~m次
    3. {n,}: n~max次
    4. *: 0~max次
    5. ?: 0~1次
    6. +: 1~max次
  9. 正则表达式的完整匹配

    1. ^: 表示匹配开头
    2. $: 持续匹配的结束
  10. 特殊符号如何匹配,在正则中:^ $ . \ [] 这些符号匹配时需要加\

  11. 条件分支 | 与分组 ()

    1. |: 表示或
    2. (): 表示一个独立的整体,括号的内容可以进行分组,单独匹配,如果不需要单独匹配功能则使用(?:)
  12. 数值的匹配. 注意事项:

    1. 把合法的数值写出来并分析规律
    2. 根据规律编写正则,并且测试非法数值
    3. 参考http://www.json.org/json-zh.html的规律分析图
  13. 中文的处理 默认中文采用的是双字节,在计算机中通过ASCII对应表来输入汉字

    1. 通过[]来设置中文的范围即可
    2. 通过escape()可以把字符串转化成ASCII编码
  14. 贪婪与懒惰

    1. 在正则中默认是贪婪模式(尽可能多的匹配)
    2. 可以在修饰数量的匹配符(* + ? {})添加?,则代表懒惰
  15. 实战

    1. 网页代码抓取图片的过程
    2. 百度首页图片抓取
    3. 过滤非法标签
    4. 正则匹配IP地址
    5. exec、test的使用

代码demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>正则表达式</title>
<style type="text/css" media="screen"> ul img { width: 100px; } ul li { display:inline; } </style>
</head>
<body>
<script type="text/javascript" charset="utf-8">

// match

// 1,2,3,4,5,6
console.info("Hello Java, hello java 2014".match(/\d\w./g));

// 7
console.info("138 158 170".match(/1[3589]\d/g));
console.info("148 168".match(/1[^3589]\d/));

// 8
console.info("15816816500".match(/1[3589]\d\d\d\d\d\d\d\d\d/));
console.info("15816816500".match(/1[3589]\d{9}/));
console.info("15816816500".match(/1[3589]\d{1,5}/));
console.info("15816816500".match(/1[3589]\d{5,}/));

// 9
console.info("phone:15816816500150167161".match(/^1[3589]\d{9}/));
console.info("15816816500150167161".match(/^1[3589]\d{9}/));
console.info("15816816500".match(/^1[3589]\d{9}$/));

// 10
console.info("[192.168.1.1]".match(/\[\d+\.\d+\.\d+\.\d+\]/));

// 11
console.info("12&3.jpeg".match(/.+\.(png|gif|jpe?g)$/));

// 12
console.info("-34.45e-2".match(/(-?)(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?/));

// 13
console.info(escape('一') + "," + unescape(escape('一')) + "," + escape('䶳'));
console.info("中国人".match(/[\u4E00-\u9FA5]/g));

// 14
console.info("aabab".match(/a.*b/g));
console.info("aabab".match(/a.*?b/g));

</script>

<!-- 15.a 网页抓取图片 -->
<ul class='ul'>

<!-- 匹配所有的图片,注意几个img的差别 -->
<li><img src='2.jpg' /></li>
<li><img alt='prompt' src="3.jpg" class='cla' ></li>
<li><IMG alt='prompt' Src="4.jpg"></li>

</ul>

<script type="text/javascript" charset="utf-8">
// 思路:部分到整体的分解步骤,罗列所有正确的格式,一个个击破:
// 第一个
console.log("图片1:<img src='img.png' />...".match(/<img\ssrc='.+'.+\/>/));
// 第二个
console.log("图片2:<img alt='prompt' src=\"3.jpg\" class='cla' >...".match(/<img.+src=['"].+['"].+\/?>/));
// 第二个
console.log("图片3:<IMG alt='prompt' Src=4.jpg>...".match(/<img.+src=['"]?.+['"]?.*\/?>/i));
// 整合在一起
// 默认在匹配的过程中是贪婪模式,在匹配多个对象时,一般来说修改成懒惰
var imgs = "图片1:<img src='img.png' />图片2:<img alt='prompt' src=\"3.jpg\" class='cla' >图片3:<IMG alt='prompt' Src=4.jpg>";
// 贪婪
console.info(imgs.match(/<img.+src=['"]?.+['"]?.*\/?>/i));
// 懒惰
console.info(imgs.match(/<img.+?src=['"]?.+?['"]?.*?\/?>/gi));

</script>

<!-- 15.b 抓取百度首页图片 -->
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
$.ajax({
url: 'data.txt',
dataType: 'html',
success: function(data) {
var srcs = data.match(/<img.+?src=['"]?.+?['"]?.*?\/?>/gi);
//console.info(srcs);
}
});

</script>
<!-- 15.c 非法标签过滤(防止html注入) 其实应该在后端实现,用js只是演示,原理是相同的 -->
<!--
html注入演示<script type="text/javascript" charset="utf-8">window.open("http://www.baidu.com", "_blank");</script>里面怎么会有百度页面呢?<iframe src="http://www.baidu.com"></iframe>需要屏蔽哦!
-->
<h3>html注入测试</h3>
<textarea id="txt" rows="8" cols="40"></textarea>
<input type="button" value="html注入测试" onclick="show();">
<script type="text/javascript" charset="utf-8">
function show() {
var txt = document.getElementById('txt').value;
console.info(txt);
txt = txt.replace(/<\/?(style|script|i?frame)(.|\n)*?>/gi, '');
console.info(txt);

var txt2 = document.getElementById('txt').value;
txt2 = txt2.replace(/<(style|script|i?frame)(.|\n)*?>*?<\/?(style|script|i?frame)(.|\n)*?>/gi, '');
console.info(txt2);
}
</script>

<!-- 15.d 正则匹配IP地址 -->
<script type="text/javascript" charset="utf-8">

// 合法的IP: 192.168.1.1 224.23.2.45 0.0.0.0 255.255.255.255

/*
拆分:
250 - 255 : 25[0-5]
200 - 249 : 2[0-4]\d
100 - 199 : 1\d{2}
0 - 99 : [1-9]?\d

*/
console.log("192.168.1.1".match(/(?:(?:25[0-5]|2[0-4]\d|[1-9]?\d|1\d{2})\.){3}(?:25[0-5]|2[0-4]\d|[1-9]?\d|1\d{2})/));
</script>

<!-- 15.3 exec和test的使用 -->
<script type="text/javascript" charset="utf-8">

var email = "19999@qq.com,xyz@163.com,20000@qq.com";

// match: 如果是全局匹配(g),那么是不支持分组的,是互斥的。
console.info(email.match(/(\d+)@qq.com/));
// 这是一个分组匹配,得到结果是"19999@qq.com", "19999"
console.info(email.match(/(\d+)@qq.com/g));
// 如果正则末尾加修饰符g,指定是全局匹配,得到"19999@qq.com", "20000@qq.com"
// 也就是说不去分组匹配了

// 为了兼容分组和全局匹配,我们可以使用RegExp:exec支持全局+分组功能,默认情况每次只查一个
var re = new RegExp(/(\d+)@qq.com/g); // 默认只查一个
console.info("lastindex:"+re.lastIndex); // 默认lastIndex = 0
console.info(re.exec(email));

// 当匹配成功,下一次继续执行索引值会存储到lastindex中
console.info("lastindex:"+re.lastIndex);
console.info(re.exec(email));

re.lastIndex = 0;
console.log(re.test(email));
</script>

</body>
</html>