第26讲
API
API即应用程序编程接口,英文全称Application Programming Interface。
API是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
正则表达式是API的一种。
1 正则表达式
1.1 正则表达式简述
正则表达式定义了字符串的模式。正则表达式并不仅限于Java语言,但是在每种语言中有细微的差别。
定义在类 Pattern
正则表达式作用
- 可以校验字符串是否满足一定的规则。
- 可以在一段文本中查找满足要求的内容。
技巧: 根据正确的数据,从左到右依次给出正则表达式。
1.2 字符类
只匹配一个字符
字符类 | 含义 |
---|---|
[abc] | 只能是abc |
[^abc] | 除了abc外的所有字符 |
[a-zA-Z] | [a, z] 并 [A, Z] |
[a-d[m-p]] | [a, d] 并 [m, p] |
[a-z&&[bc]] | [a, z] 交 字符’b’‘c’ |
[a-z&&[ ^bc ]] | [a, z] 交 非字符’b’‘c’。等同于[ad-z] |
[a-z&&[ ^m-p ]] | [a, z] 交 非[m, p]。等同于[a-lq-z] |
(ab|c|[d-i]) | ‘a’‘b’ 并 ‘c’ 并 [d, i] |
1.3 预定义字符
只匹配一个字符
预定义字符 | 含义 |
---|---|
. | 任何字符,除了’\n’ |
\d | 数字字符匹配。等效于 [0-9]。 |
\D | 非数字字符匹配。等效于 [ ^0-9 ]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v ] 等效。 |
\S | 匹配任何非空白字符。与 [ ^ \f\n\r\t\v ] 等效。 |
\w | 匹配任何字类字符,包括下划线。与"[ A-Za-z0-9_ ]"等效。 |
\W | 与任何非单词字符匹配。与"[ ^A-Za-z0-9_ ]"等效。 |
[] | 里面的内容只出现一次 |
() | 分组。表示()里的内容是一个整体。 |
| | 写在[]外表示并集。方括号里什么都不写就是并集 |
&& | 交集。一个&表示字符’&’ |
\
转义字符:用来改变其后紧跟的一个字符的含义。
在其他语言中,\\
表示:我要在正则表达式中插入一个普通的反斜杠,不要给它任何特殊的意义。
在Java中,\\
表示:我要插入一个正则表达式的反斜线,所以其后紧跟的一个字符具有特殊的意义。
即在 Java 的正则表达式中,两个\\
代表其他语言中的一个\
,这也就是为什么表示一位数字的正则表达式是\\d
,而表示一个普通的反斜杠是\\
。
1.4 数量词
可以匹配多个字符
数量词 | 含义 |
---|---|
X? | 字符X出现0次或1次 |
X* | 字符X出现0次或多次 |
X+ | 字符X出现1次或多次 |
X{n} | 字符X恰好出现n次 |
X{n,} | 字符X至少出现n次 |
X{n, m} | 字符X最少出现n次,最多出现m次 |
(?i) | 忽略后面所有字符的大小写。a((?i)b)c,表示只忽略b的大小写 |
public class Demo {
public static void main(String[] args) {
//由字母、数字、下划线组成的至少6位字符串
System.out.println("hello_2022".matches("\\w{6,}")); //true
System.out.println("hi_i".matches("\\w{6,}")); //false
//由字母、数字组成的6位字符串
System.out.println("hi2022".matches("[\\w&&[^_]]{6}")); //true
System.out.println("hi22".matches("[\\w&&[^_]]{6}")); //false
}
}
使用正则表达式一般是改写已经写好的。插件名:
any-rule
。使用方法:项目窗口右键选择AnyRule
2 捕获分组
2.1 分组
表示时间的正则表达式 "([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d"
其中([01]\\d|2[0-3])
就是分的一个组, ()
是表示分组的符号。
- 每个组都是有组号的,即序号。
1.组号从1开始,连续不间断。
2.以左括号为基准,最左边的是第一组,以此类推。
( A ( B ) )( C )
// A是第一组
// B是第二组
// C是第三组
2.2 捕获分组
捕获分组就是把这一组的数据捕获出来,再用一次。
语法:
在正则表达式内部: \\X
在正则表达式外部: $X
//捕获第X组的数据
在正则表达式内部
public class RegexDemo7 {
public static void main(String[] args) {
//判断一个字符串的开始部分与结束部分是否一致
//q243q 12java12 @!sig@s
String regex1 = "(.+).+\\1";
System.out.println("q243q".matches(regex1)); //true
System.out.println("12java12".matches(regex1)); //true
System.out.println("@!sig@s".matches(regex1)); //false
//判断一个字符串的开始部分与结束部分是否一致,且开始结束部分里的字符也要一致
//000inside000 &&1002&& 0vObject0vO
String regex2 = "((.)\\2*).+\\1";
System.out.println("000inside000".matches(regex2)); //true
System.out.println("&&1002&&".matches(regex2)); //true
System.out.println("0vObject0vO".matches(regex2)); //false
}
}
在正则表达式外部
//将重复内容替换为单个字符
//"我要吃吃吃吃吃吃吃吃饭饭饭饭饭"替换成"我要吃饭"
public class RegexDemo8 {
public static void main(String[] args) {
String str = "我要吃吃吃吃吃吃吃吃饭饭饭饭饭";
// $1:在正则表达式外部使用一次分组1
String result = str.replaceAll("(.)\\1+", "$1");
System.out.println(result); //我要吃饭
}
}
2.3 非捕获分组
匹配正则表达式但不捕获匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。
不占用组号
符号 | 说明 |
---|---|
(?: regex) | 获取所有 |
(?= regex) | 获取前面部分 |
(?! regex) | 获取不是指定内容的前面部分 |
3 爬虫
3.1 爬虫基础
爬虫,即网络爬虫,也叫做网络机器人,可以代替人们自动地在互联网中进行数据信息的采集与整理,大家可以理解为在网络上爬行的一只蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛,如果它遇到自己的猎物(所需要的资源),那么它就会将其抓取下来。
需要的类
类 | 说明 |
---|---|
Pattern | 模式类,正则表达式的编译表示形式。没有公共构造方法。 |
Matcher | 对输入字符串进行解释和匹配操作,即文本匹配器。没有公共构造方法。 |
需要的方法
static Pattern compile(String regex) | 使用给定的正则表达式创建Pattern的对象。 |
Matcher matcher(CharSequence input) | 创建Pattern的对象对应的Matcher的对象。 |
boolean find() | 获取与该模式匹配的子串的开始索引和结束索引加一,[start, end+1) |
String group() | 返回由匹配操作所获取的索引截取的子串。 |
对于具有输入序列 str 的匹配器 m ,表达式
m.group()
和str.substring(m.start(), m.end())
是等效的。
例:
/*
在如下字符串中爬取JavaXXX
”2005年6月,在JavaOne大会上,Sun公司发布了JavaSE6。此时,Java的各种版本已经更名,已取消其中的数字2,如J2EE更名为JavaEE,J2SE更名为JavaSE,J2ME更名为JavaME。“
*/
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Demo {
public static void main(String[] args) {
String str = "2005年6月,在JavaOne大会上,Sun公司发布了JavaSE6。此时,Java的各种版本已经更名,已取消其中的数字2,如J2EE更名为JavaEE,J2SE更名为JavaSE,J2ME更名为JavaME。";
//使用给定的正则表达式创建Pattern的对象
Pattern pattern = Pattern.compile("Java\\w{2,3}");
//创建Pattern的对象对应的模式匹配器。
//理解:使用matcher去读取str大串,去找符合pattern规则的子串
Matcher matcher = pattern.matcher(str);
//利用循环打印截取到的子串
while (matcher.find()) {
String group = matcher.group();
System.out.print(group + " ");
//JavaOne JavaSE6 JavaEE JavaSE JavaME
}
}
}
3.2 贪婪爬取
贪婪爬取:在爬取数据的时候尽可能的多获取数据。
非贪婪爬取:在爬取数据的时候尽可能的少获取数据。
- Java中,默认是贪婪爬取。在数量词后加’?',就是非贪婪爬取。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Demo {
public static void main(String[] args) {
String str = "abbbbbbbbbbbbbbbbbbbb";
//贪婪爬取:尽可能多的获取数据
Pattern p1 = Pattern.compile("ab+");
Matcher m1 = p1.matcher(str);
while (m1.find()) {
String s = m1.group();
System.out.println(s); //abbbbbbbbbbbbbbbbbbbb
}
//非贪婪爬取:尽可能少的获取数据
Pattern p2 = Pattern.compile("ab+?");
Matcher m2 = p2.matcher(str);
while (m2.find()) {
String s = m2.group();
System.out.println(s); //ab
}
}
}
4 正则表达式在字符串中的使用
方法 | 说明 |
---|---|
public String[] matches(String regex) | 此字符串是否匹配给定的正则表达式 |
public String replaceAll(String regex, 替换成的内容) | 将字符串按照正则表达式规则替换,返回一个新字符串 |
public String[] split(String regex) | 将字符串按照正则表达式规则切割,返回一个字符串数组 |
public class Demo {
public static void main(String[] args) {
//1.将字符串按照正则表达式规则替换,返回一个新字符串
String str = "汤姆asikndlkahbf是猫jkashbfkjagbf不是狗";
String regex = "[\\w&&[^_]]+";
String s = str.replaceAll(regex, ", ");
System.out.println(s); //汤姆, 是猫, 不是狗
//2.将字符串按照正则表达式规则切割,返回一个字符串数组
String[] arr = str.split(regex);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]); //汤姆是猫不是狗
}
}
}