2.常用API(爬虫,正则表达式)
常用API(爬虫,正则表达式)
爬虫
本地爬虫:Pattern:表示正则表达式;
Matcher:文本匹配器,作用按照正则表达式的规则读取字符串,从头开始读取,在大串中去找符合匹配规则的子串;
find:1.拿着文本匹配器从头开始读取,寻找是否有满足规则的子串;如果没有,方法返回false;如果有:返回true。在 底层记录子串的起始索引和结束索引+1(包头不包尾巴);
2.第二次在调用find的时候,会继续读取后面的内容;读取到第二个满足要求的子串,方法会继续返回true;并把 第二个子串的起始索引和结束索引+1,进行记录;
group:方法底层会根据find方法记录的索引进行字符串的截取;第二次调用group方法的时候,会根据find方法记录的索 引再次截取子串;
例子:
package com.caihongjia.a07regexdemo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo03 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,"+
"因为这两个是长期支持版本,下一个长期支持版本是Java17,相信未来不久Java17也会逐渐登上历史舞台";
//method1();
//1.获取正则表达式的对象
Pattern p = Pattern.compile("Java\\d{0,2}");
//2.获取文本匹配器的对象
Matcher m = p.matcher(str);
//3.利用循环获取
while(m.find()){
String s = m.group();
System.out.println(s);
}
}
private static void method1() {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,"+
"因为这两个是长期支持版本,下一个长期支持版本是Java17,相信未来不久Java117也会逐渐登上历史舞台";
//Pattern:表示正则表达式
//Matches:文本匹配器,作用按照正则表达式的规则读取字符串,从头开始读取
// 在大串中去找符合匹配规则的子串。
//获取正则表达式的对象
Pattern p = Pattern.compile("Java\\d{0,2}");
//获取文本匹配器的对象
//m:文本匹配器的对象
//str:大串
//p:规则
//m要在str中找符合p规则的小串
Matcher m = p.matcher(str);
//拿着文本匹配器从头开始读取,寻找是否有满足规则的子串
//如果没有,方法返回false
//如果有:返回true。在底层记录子串的起始索引和结束索引+1
//0,4
boolean b = m.find();
//方法底层会根据find方法记录的索引进行字符串的截取
//subString(起始索引,结束索引);包头不包尾
//(0,4)但是不包含4索引
//会把截取的小串进行返回
String s1 = m.group();
System.out.println(s1);
//第二次在调用find的时候,会继续读取后面的内容
//读取到第二个满足要求的子串,方法会继续返回true
//并把第二个子串的起始索引和结束索引+1,进行记录
b = m.find();
//第二次调用group方法的时候,会根据find方法记录的索引再次截取子串
String s2 = m.group();
System.out.println(s2);
boolean b1 = m.find();
String s3 = m.group();
System.out.println(s3);
}
}
有条件的爬取:?理解为前面的数据Java
=表示在Java后面要跟随的数据,但是在获取的时候,只获取前半部分
:表示在Java后面要跟随的数据,但是在获取的时候,获取全部数据
!表示在Java后面要跟随的数据,获取除了与后面数据有关的以外的全部前面数据
例子:
package com.caihongjia.a07regexdemo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo04 {
public static void main(String[] args) {
/*
需求1:爬取版本号为8,11,17的Java文本,但是只要Java,不显示版本号
需求2:爬取版本号为8,11,17的Java文本,正确爬取结果为:Java8 Java11 Java17
需求3:爬取版本号为8,11,17的Java文本
*/
String str = "java自从95年问世以来,经历了很多版本,目前企业中用的最多的是JAva8和Java11,"+
"因为这两个是长期支持版本,下一个长期支持版本是JAVa17,相信未来不久JAVA17也会逐渐登上历史舞台";
//1.定义正则表达式
//2.?理解为前面的数据Java
//3.=表示在Java后面要跟随的数据
//4.但是在获取的时候,只获取前半部分
//需求1
String regex1 = "((?i)Java)(?=8|17|11)"; //?i忽略大小写
//需求2
String regex2 = "((?i)Java)(8|17|11)";
String regex3 = "((?i)Java)(?:8|17|11)";
//需求3
String regex4 = "((?i)Java)(?!8|17|11)";
Pattern p = Pattern.compile(regex4);
Matcher m = p.matcher(str);
while(m.find()){
System.out.println(m.group());
}
System.out.println("============================");
}
}
贪婪爬取:在爬取数据的时候尽可能的多获取数据,Java中,默认的就是贪婪爬取 ab+
非贪婪爬取:在爬取数据的时候尽可能的少获取数据,如果我们在数量词+或者* 的后面加上问号,那么此时就是非贪婪爬取 ab+?
例子:
package com.caihongjia.a07regexdemo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo05 {
public static void main(String[] args) {
//贪婪爬取:在爬取数据的时候尽可能的多获取数据 ab+
//非贪婪爬取:在爬取数据的时候尽可能的少获取数据 ab+?
//ab+:
//贪婪爬取:abbbbbbbb
//非贪婪爬取:ab
//Java中,默认的就是贪婪爬取
//如果我们在数量词+或者* 的后面加上问号,那么此时就是非贪婪爬取
String str = "java自从95年问世以来,abbbbbbbbbbbbbbb经历了很多版本,目前企业中用的最多的是JAva8和Java11,"+
"因为这两个是长期支持版本,下一个长期支持版本是JAVa17,相信未来不久JAVA17也会逐渐登上历史舞台";
String regex = "ab+?";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
while(m.find()){
System.out.println(m.group());
}
}
}
正则表达式补充方法:
replaceAll(String regex,String newStr) :按照正则表达式的规则进行替换
细节:方法在底层跟之前一样也会创建文本解析器的对象
然后从头开始去读取字符串中的内容,只要有满足的,那么就使用第二个参数去替换
例子:
package com.caihongjia.a07regexdemo;
public class RegexDemo06 {
public static void main(String[] args) {
//public String replaceAll(String regex,String newStr) 按照正则表达式的规则进行替换
//Public String[] split(String regex) 按照正则表达式的规则切割字符串
/*
有一段字符串:小诗诗qwertyuiop123小丹丹qwertyuiop123小慧慧
要求1:把字符串中三个名字之间的字母替换为vs
要求2:把字符串中的三个名字分割出来
*/
String s = "小诗诗qwertyuiop123小丹丹qwertyuiop123小慧慧";
//细节:
//方法在底层跟之前一样也会创建文本解析器的对象
//然后从头开始去读取字符串中的内容,只要有满足的,那么就使用第二个参数去替换
String result1 = s.replaceAll("[\\w&&[^_]]+", "vs");
System.out.println(result1);
}
}
split(String regex):按照正则表达式的规则切割字符串
例子:
package com.caihongjia.a07regexdemo;
public class RegexDemo06 {
public static void main(String[] args) {
//public String replaceAll(String regex,String newStr) 按照正则表达式的规则进行替换
//Public String[] split(String regex) 按照正则表达式的规则切割字符串
/*
有一段字符串:小诗诗qwertyuiop123小丹丹qwertyuiop123小慧慧
要求1:把字符串中三个名字之间的字母替换为vs
要求2:把字符串中的三个名字分割出来
*/
String s = "小诗诗qwertyuiop123小丹丹qwertyuiop123小慧慧";
//细节:
//方法在底层跟之前一样也会创建文本解析器的对象
//然后从头开始去读取字符串中的内容,只要有满足的,那么就使用第二个参数去替换
// String result1 = s.replaceAll("[\\w&&[^_]]+", "vs");
// System.out.println(result1);
String[] arr = s.split("[\\w&&[^_]]+");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
正则表达式分组:捕获分组和非捕获分组
捕获分组:
概念:可以获取每组中的内容反复使用;
组号的特点:从1开始,连续不间断;以左括号为基准,最左边的是第一组;
非捕获分组:
概念:分组之后不需要再用本组数据,仅仅把数据括起来,不占组号;
(?😃(?=)(?!)都是非捕获分组;
例子:
package com.caihongjia.a07regexdemo;
public class RegexDemo07 {
public static void main(String[] args) {
//分组:
//每组是有组号的,也就是序号。
//规则1:从1开始,连续不间断
//规则2:以左括号为基准,最左边的是第一组,其次为第二组,以此类推
//需求1:判断一个字符串的开始字符和结束字符是否一致?只考虑一个字符
//举例:a123a b456b 17891 &abc& a123b(false)
// \\组号:表示把第x组的内容再出来用一次
String regex1 = "(.).+\\1";
System.out.println("a123a".matches(regex1));
System.out.println("b456b".matches(regex1));
System.out.println("17891".matches(regex1));
System.out.println("&abc&".matches(regex1));
System.out.println("a123b".matches(regex1));
System.out.println("--------------------------------------");
//需求2:判断一个字符串的开始部分和结束部分是否一致?可以有多个字符
//举例:abc123abc b456b 123789123 &!@abc&!@ abc123abd(false)
String regex2 = "(.+).+\\1";
System.out.println("abc123abc".matches(regex2));
System.out.println("b456b".matches(regex2));
System.out.println("123789123".matches(regex2));
System.out.println("&!@abc&!@".matches(regex2));
System.out.println("abc123abd".matches(regex2));
System.out.println("--------------------------------------");
//需求3:判断一个字符串的开始部分和结束部分是否一致?开始部分内部每个字符也需要一致
//举例:aaa123aaa bbb456bbb 111789111 &&abc&&
//* 0次或多次
//(.):把首字母看做一组
// \\1:把首字母拿出来再次使用
// *:作用于\\1,表示后面重复的内容出现0次或多次
String regex3 = "((.)\\2*).+\\1";
System.out.println("aaa123aaa".matches(regex3));
System.out.println("bbb456bbb".matches(regex3));
System.out.println("111789111".matches(regex3));
System.out.println("&&abc&&".matches(regex3));
System.out.println("aaa123aab".matches(regex3));
System.out.println("--------------------------------------");
}
}
package com.caihongjia.a07regexdemo;
public class RegexDemo08 {
public static void main(String[] args) {
//捕获分组:后续还要继续使用本组的数据
//正则内部使用:\\组号
//正则外部使用:\\$组号
/*
需求:
将字符串:我要学学编编编编程程程程程程
替换为:我要学编程
*/
String str = "我要学学编编编编程程程程程程";
//需求:把重复的内容 替换为 单个的
//学学 学
//编编编编 编
//程程程程程程 程
//(.):表示把重复内容的第一个字符看做一组
//\\1表示第一字符再次出现
//+ 至少一次
//$1: 表示把正则表达式中第一组的内容,再拿出来用
String s1 = str.replaceAll("(.)\\1+", "$1");
System.out.println(s1);
}
}
package com.caihongjia.a07regexdemo;
public class RegexDemo09 {
public static void main(String[] args) {
/*
非捕获分组:分组之后不需要再用本组数据,仅仅是把数据括起来
身份证号码:
41080119930228457x
510801197609022309
15040119810705387X
*/
//身份证号码的简易正则表达式
//非捕获分组:仅仅是把数据括起来
//特点:不占用组号
//这里\\1报错原因:(?:)就是非捕获分组,此时是不占用组号的。
//(?:) (?=) (?!) 都是非捕获分组‘
//更多使用第一个
String regex1 = "[1-9]\\d{16}(?:\\d|X|x)\\1";
String regex2 = "[1-9]\\d{16}(\\d|X|x)\\1";
System.out.println("41080119930228457x".matches(regex));
}
}
浙公网安备 33010602011771号