编程环境
-
windows 10
-
eclipse
前言
在一次Java程序设计课程中,在课堂上了解到了正则表达式,然后自己去百度了一番,发现正则表达式应用的范围还是比较广泛的,在Python爬虫爬取数据时候,也会用上正则表达式,所以决定花点心思去学习一下正则表达式。
正则表达式语法
- 普通字符
正则表达式 | 说明 |
---|---|
[123abc] | 匹配[…]括号里边的所有字符,相当于匹配1或2或3或a或b或c, 等价于[1|2|3|a|b|c] |
[^123abc] | 匹配除了[…]之外的所有字符,相当于匹配除了1,2,3,a,b,c之外的所有字符 |
[a-z] | 表示一个区间,匹配小写字母 |
[A-Z] | 表示一个区间,匹配大写字母 |
[0-9] | 表示一个区间,匹配0到9之间的数字 |
\d | 匹配数字,等价于[0-9] |
\D | 匹配非数字,等价于[^0-9] |
\w | 匹配字母、数字或者下划线,等价于[a-zA-z0-9_] |
\W | 匹配非字母、非数字或者非下划线,\W相当于匹配\w的补集字符,等价于[^a-zA-z0-9_] |
说明:\大写字母 和 \小写字母,匹配的字符内容是相反的,^代表取反的意思
- 非打印字符
正则表达式 | 说明 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 control-M 或回车符。x 的值必须是26个字母 |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\t | 匹配一个制表符 |
\v | 匹配一个垂直制表符 |
\s | 匹配所有的空白字符,等价于[\f\n\r\t\v] |
\S | 匹配所有非空白字符,等价于[^\f\n\r\t\v] |
说明:控制字符主要有LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(振铃)等,存在于Ascii码中的第0~31号及127号中。想了解更多关于控制字符的内容请点击这里
- 特殊字符
正则表达式 | 说明 |
---|---|
$ | 匹配输入字符串的结尾位置,要匹配 $ 字符本身,请使用\$。 |
( ) | 标记一个子表达式的开始和结束位置,要匹配这些字符,请使用 \( 和 \) |
* | 匹配前面的子表达式零次或多次,要匹配 * 字符,请使用 \* |
+ | 匹配前面的子表达式一次或多次,要匹配 + 字符,请使用 \+ |
. | 匹配除换行符 \n 之外的任何单个字符,要匹配 . ,请使用 \. |
[ | 标记一个中括号表达式的开始。要匹配 [ ,请使用 \[ |
? | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符,要匹配 ? 字符,请使用 ? |
\ | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符 |
^ | 匹配输入字符串的开始位置,当该符号在方括号表达式中使用时,匹配非方括号内容的字符,相当于取反,要匹配 ^ 字符本身,请使用 ^ |
{ | 标记限定符表达式的开始,要匹配 {,请使用 \{ |
| | 指明两项之间的一个选择,相当于或,要匹配 |,请使用 | |
- 限定字符
正则表达式 | 说明 |
---|---|
{n} | n 是一个非负整数,匹配确定的 n 次 |
{n,} | n 是一个非负整数,至少匹配n 次 |
{n,m} | m 和 n 均为非负整数,其中n <= m,最少匹配 n 次且最多匹配 m 次 |
正则表达式的应用
- 实例1
我们来讲一下比较有用的例子吧,拿html的标签页来举例子,假如说我们需要匹配html中a标签下的链接
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Debug {
public static void main(String[] args) {
String html = "<a class=\"regex\" href=\"https://www.baidu.com/\">正则表达式</a>";
String regex = "<a class=\"[a-z]+\" href=\"(.*?)\">(.*?)</a>";
for (int i = 0; i < 3; i++) {
String content = getContentByRegex(html, regex, i);
System.out.println(content);
}
}
public static String getContentByRegex(String html, String regex, int index) {
String content = ""; // 如果没有匹配到, 则返回空字符串
Pattern pattern = Pattern.compile(regex);
Matcher match = pattern.matcher(html);
if (match.find()) {
content = match.group(index);
}
return content;
}
}
解释说明一下上面的代码,html是我们获取到的网页源代码,regex就是我们写的正则表达式规则,可以看到的是,我在href=后边使用了 .*? ,.*? 指的是匹配除了换行之外的所有字符,在这个代码里边就是匹配href后边的整个链接(ps: .*? 在写在href双引号的里边), .*? 我个人觉得是比较常用的一种,简单好用。接下来就是调用自己写的函数来返回匹配的内容,其中match.find()是必不可少的,match.group(0)或者match.group()代表的是正则表达式规则的全部内容,match.group(1)代表的是第一个括号里边的内容,match.group(2)代表的是第二个括号里边的内容,依次类推。
代码的运行结果如下
<a class="regex" href="https://www.baidu.com/">正则表达式</a>
https://www.baidu.com/
正则表达式
如果我们只需要href里边的链接,我们就只需要match.group(1)就可以了。
- 实例2
那如果我们想匹配网页上所有a标签下的链接的话,该怎么做呢?先上代码
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.List;
import java.util.ArrayList;
public class Debug {
public static void main(String[] args) {
String html = "<a class=\"regex\" href=\"https://www.baidu.com/\">正则表达式\n</a>隔开两个a标签的内容\n<a class=\"regex\" href=\"https://blog.csdn.net/\">正则表达式\n</a>";
String regex = "<a class=\"[a-z]+\" href=\"(.*?)\">(.*?)</a>"; // 正则表达式规则
List<String> content = getContentByRegex(html, regex, 1); // 获取到的内容
System.out.println(content); // 输出
}
public static List<String> getContentByRegex(String html, String regex, int index) {
List<String> list = new ArrayList<>(); // 创建一个空列表
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
Matcher match = pattern.matcher(html);
while (match.find()) {
list.add(match.group(index));
}
return list;
}
}
解释说明:因为我们需要匹配多个a标签下的链接,所以我们用列表来存储这些链接比较方便,对比上一个例子,会发现compile中多了一个Pattern.DOTALL, 原来 .*? 匹配的是除了换行之外的所有字符,使用DOTALL会把\n也当成一个普通字符,也就是说 .*? 也会匹配换行符;还有就是在getContentByRegex函数中用的是while (match.find()) 而不是if (match.find()),因为这里是有多个链接的,所有用的是while。
代码的运行结果如下
[https://www.baidu.com/, https://blog.csdn.net/]
我们来输出一下match.group(2),输出结果如下:
[正则表达式
, 正则表达式
]
会发现,也把 \n 符匹配了进去,所以输出时候文字后边会多了一个 \n ,这也就是使用DOTALL的原因,如果没有使用DOTALL则会匹配失败,返回的是空列表 [] 。
总结
上述就是我对正则表达式的理解,讲到的内容可能偏少,不过都是比较实用的东西。希望这篇文章会对你有帮助,如果有什么问题欢迎在评论区提出。