经过之前对于API的学习:JAVA基础 —— API
接下来的文章让我们来了解一下不同类下的方法,但是这些方法不要去背。
而是要去记一下类名和类作用,也可以在以后去查阅API帮助文档。
Math、System、Runtime和Object | JAVA基础 (常用API)—— Math、System、Runtime和Object |
BigInteger和BigDecimal | JAVa基础(常用API) —— BigInteger和BigDecimal |
正则表达式 | JAVA基础(常用API) —— 正则表达式 |
时间相关类 | JAVA基础(常用API) —— 时间相关类 |
包装类 | JAVA基础(常用API) —— 包装类 |
目录
import java.util.regex.Pattern 正则表达式包
import java.util.regex.Matcher 文本匹配器包
作用1 :正则表达式可以校验字符串是否满足一定的规则,并用来校验数据格式的合法性。
作用2 :正则表达式可以在一段文字中查找满足要求的内容。
正则表达式在字符串方法中的使用:
方法名 说明 public String[ ] matches(String regex) 判断是否与正则表达式匹配 public String replaceAll (String regex,String newStr) 按照正则表达式的规则进行替换 public String[ ] spilt (String regex) 按照正则表达式的规则进行切割字符串
一、 校验字符串
1. 字符类
字符类(只匹配一个字符):
public class matchesTest {
public static void main(String[] args) {
// 一个大括号只能是一个字符
// 只能是a b c
System.out.println("a".matches("[abc]")); // true
System.out.println("z".matches("[abc]")); // false
System.out.println("ab".matches("[abc]")); // false
System.out.println("ab".matches("[abc][abc]")); // true
// 不能出现a b c
System.out.println("a".matches("[^abc]")); // fasle
System.out.println("zz".matches("[^abc]")); // fasle
// a到z A到Z(包括头尾范围)
System.out.println("b".matches("[a-zA-Z]")); // true
System.out.println("0".matches("[a-zA-Z]")); // fasle
// [a-d[m-p]] a到d 或者 m到p
System.out.println("b".matches("[a-d[m-p]]")); // true
System.out.println("e".matches("[a-d[m-p]]")); // fasle
// [a-z&&[def]] a-z和def的交集
// 细节:如果要求两个范围的交集 需要写&&
// 如果写成了一个& 就不表示交集 只是单单一个符号而已
System.out.println("a".matches("[a-z&&[def]]")); // true
System.out.println("&".matches("[a-z&&[def]]")); // false
// [a-z&&[^bc]] a-z 和 非bc 的交集
System.out.println("a".matches("[a-z&&[^bc]]")); // true
System.out.println("b".matches("[a-z&&[^bc]]")); // false
// [a-z&&[^m-p]] a到z和除了m到p的交集
System.out.println("a".matches("[a-z&&[^m-p]]")); // true
System.out.println("m".matches("[a-z&&[^m-p]]")); // false
}
}
2. 预定义字符
预定义字符(只匹配一个字符):
public class matchesTest {
public static void main(String[] args) {
// \表示转义字符 :改变后面字符原本含义
// 练习:以字符串形式打印一个双引号
// System.out.println("\"");
// .表示任意一个字符
System.out.println("你".matches(".")); // true
System.out.println("你a".matches("..")); // true
// \\d 只能是任意一个数字
// 简单来说 两个\表示一个\
System.out.println("a".matches("\\d")); // fasle
System.out.println("3".matches("\\d")); // true
System.out.println("333".matches("\\d")); // fasle
System.out.println("333".matches("\\d\\d\\d")); // true
// \\w只能是一个单词字符 [a-zA-Z0-9]
System.out.println("z".matches("\\w")); // true
System.out.println("21".matches("\\w")); // false
System.out.println("你".matches("\\w")); // fasle
System.out.println("-".matches("\\w")); // true
// 非单词字符
System.out.println("你".matches("\\W")); // true
// 以上正则表达式只能校验单个字符
}
}
3. 数量词
public class matchesTest {
public static void main(String[] args) {
//必须是数字 字母 下划线 至少 6位
System.out.println("2442fsfsf".matches("\\w{6,}")); //true
System.out.println("244f".matches("\\w{6,}")); //false
//必须是数字和字符 必须是 4位
System.out.println("23dF".matches("[a-zA-Z0-9]{4}")); //true
System.out.println("23_F".matches("[a-zA-Z0-9]{4}")); //false
System.out.println("23dF".matches("\\w&&[^_]{4}")); //true
System.out.println("23_F".matches("\\w&&[^_]{4}")); //fasle
}
}
4. 练习
需求:
请编写正则表达式验证用户输入的手机号码是否满足要求。请编写正则表达式验证用户输入的邮箱号是否满足要求。
请编写正则表达式验证用户输入的电话号码是否满足要求。
public class matchesTest {
public static void main(String[] args) {
//手机号: 三部分
//一、 1 表示手机号码只能由1开头
//二、 [3-9] 表示手机号码第二位只能是3-9之间
//三、\\d{9} 表示任意数字可以出现9次,也只能出现9次
String regex1 = "1[3-9]\\d{9}";
System.out.println("13112345678".matches(regex1)); //true
System.out.println("131123456789".matches(regex1)); //fasle
//座机号码: 三部分
//一、区号: 0表示区号只能以0开头
// \\d{2,3} 表示区号从二位开始可以是任意数字,可以出现2~3次
//二、 - ?表示次数 次数0次或者1次
//三、 号码 第一位不能以0开头;从第二位开始可以为任意数字 ;号码总长度: 5-10位
String regex2 = "0\\d{2,3}-?[1-9]\\d{4,9}";
System.out.println("020-2324242".matches(regex2)); //true
//邮箱号码 :三部分
//一、 @左边 \\w+任意字符数字下划线至少出现一次就行
//二、 @只能出现一次
//三、 .的左边可以是字母和数字 [\\w&&[^_]] 任意字符数字总共出现2-6次 {2,6}
// . \\.
// .的右边 所有的大写字母和小写字母 只能出现2-3次 [a-zA-Z]{2,3}
String regex3 = "\\w+@[\\w&&[^_]]{2,6}\\.[a-zA-Z]{2,3}";
System.out.println("zhangsan@163.com".matches(regex3)); //true
//24小时
String regex4 = "([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
System.out.println("23:11:11".matches(regex4)); //true
String regex5 = "([01]\\d|2[0-3])(:[0-5]\\d){2}";
System.out.println("23:11:11".matches(regex5)); //true
}
}
二、 爬虫
在一段文字中查找满足要求的内容。
1. 本地爬虫
通过一个小练习来了解什么是本地爬虫:
有如下文本,请按照要求爬取数据。
Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台。
要求:找出里面所有的JavaXX
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class regexTest {
public static void main(String[] args) {
String str = " Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是"
+ "Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,"
+ "相信在未来不久Java17也会逐渐登上历史舞台。";
// 获取正则表达式对象
Pattern p = Pattern.compile("Java\\d{0,2}");
// 获取文本匹配器对象
Matcher m = p.matcher(str);
while(m.find()) {
//知道字符串末尾 find为false
String s=m.group();
System.err.println(s);
}
}
public static void method1(String str) {
// Pattern:表达正则表达式
// Matcher:文本匹配器 作用:按照正则表达式规则读取字符串,从头读取,找到符合规则的子串
// 获取正则表达式对象
Pattern p = Pattern.compile("Java\\d{0,2}");
// 获取文本匹配器对象
// m: 文本匹配器的对象
// str:大串
// p:规则
// 即 m要在str中找到符合p规则的小串
Matcher m = p.matcher(str);
// 拿着文本匹配器从头开始读取,寻找是否有满足规则子串
// 如果有,返回true,并且在底层记录子串的起始索引和结束索引+1
// Java : 0,4
// 如果没有,返回false
boolean flag = m.find();
// 方法底层根据find方法记录的索引进行字符串的截取
// subString(起始索引,结束索引) 包头不包尾
// (0,4) 但是不包含4索引
// 会把截取的小串返回
String s1 = m.group();
System.out.println(s1);
//第二次在调用find的时候,会维续读取后面的内容
//读取到第二个满足要求的子串,方法会继续返回true
//并把第二个子串的起始索引和结束索引+1,进行记录
flag = m.find();
//第二次调用group方法的时候,会根据find方法记录的索引再次截取子串
String s2 = m.group();
System.out.println(s2);
}
}
爬取小规则:
1.1 带条件爬取
需求1:爬取版本号为8,11,17的]ava文本,但是只要]ava,不显示版本号。
需求2:爬取版本号为8,11,17的ava文木。正确爬取结果为: Java8 JAva11 JAVa17 JAVA17。需求3:爬取除了版本号为8,11,17的Java文本。
public class regexTest {
public static void main(String[] args) {
String str = " Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是"
+ "Java8和JAva11,因为这两个是长期支持版本,下一个长期支持版本是JAVa17,"
+ "相信在未来不久JAVA17也会逐渐登上历史舞台。";
//1.定义正则表达式
//? 表示前面的数据java
// = 表示在java后面要跟随的数据
//但是在获取的时候,只获取后半部分
//需求1
String regex = "((?i)Java)(?=8|11|17)";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
while (m.find()) {
System.out.print(m.group() + ",");
}
System.out.println();
//需求2
String regex1 = "((?i)Java)(8|11|17)";
Pattern p1 = Pattern.compile(regex1);
Matcher m1 = p1.matcher(str);
while (m1.find()) {
System.out.print(m1.group() + ",");
}
System.out.println();
String regex2 = "((?i)Java)(?:8|11|17)";
Pattern p2 = Pattern.compile(regex2);
Matcher m2 = p2.matcher(str);
while (m2.find()) {
System.out.print(m2.group() + ",");
}
System.out.println();
//需求3
// !去除的意思
String regex3 = "((?i)Java)(?!8|11|17)";
Pattern p3 = Pattern.compile(regex2);
Matcher m3 = p3.matcher(str);
while (m3.find()) {
System.out.print(m3.group() + ",");
}
}
}
1.2 贪婪爬取和非贪婪爬取
贪婪爬取 | 在爬取数据的时候尽可能多的获取数据库 |
非贪婪爬取 | 在爬取数据的时候尽可能少的获取数据库 |
需求1:按照ab+的方式爬取ab,b尽可能多获取
需求2:按照ab+的方式爬取ab,b尽可能少获取
public class regexTest {
public static void main(String[] args) {
//Java当中,默认的就是贪婪爬取
//如果我们在数量词 + * 的后面加上问号 那么就是非贪婪爬取
String str = " Java自从95年问世以来,abbbbbbbbbbbbb" +
"经历了很多版本,目前企业中用的最多的是"
+"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());
}
String regex1 = "ab+?";
Pattern p1 = Pattern.compile(regex1);
Matcher m1=p1.matcher(str);
while (m1.find()) {
System.out.println(m1.group());
}
}
}
2. 网络爬虫
通过下面代码来了解什么是网络爬虫:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class regexTest {
public static void main(String[] args) {
//将某个URL网址中所有的身份证号码提取出来
//创建一个URL对象
URL url = new URL();
//连接上网址
//细节:保证网络是畅通的
URLConnection conn = url.openConnection();
//创建一个对象去读取网路中的数据
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
//获取正则表达式对象
String regex = "[1-9]\\d{17}";
Pattern pattern = Pattern.compile(regex);
//在读取的时候每次读一整行
while((line = br.readLine())!=null) {
System.out.println(line);
//拿着文本匹配器的对象matcher按照pattern的规则去读取当前这一行信息
Matcher m = pattern.matcher(line);
while(m.find()) {
System.out.println(m.group());
}
}
}
}
三、分组
分组就是一个小括号。
每组是有组号的,也就是序号。
规则1:从1开始,连续不间断。
规则2:以左括号为基准,最左边的是第一组,其次为第二组,以此类推。
1. 捕获分组
捕获分组(默认)就是把这一组的数据捕获出来,再用一次。
组号的特点:
从1开始,连续不间断;以左括号为基准,最左边的是第一组。
正则内部使用 \\组号 正则外部使用 $组号
需求1:判断一个字符串的开始字符和结束字符是否一致?只考虑一个字符
举例::a123a b456b 17891 &abc&需求2:判断一个字符串的开始部分和结束部分是否一致?可以有多个字符
举例:abc123abc b456b 123789123 &!@abc&!@
需求3:判断一个字符串的开始部分和结束部分是否一致?开始部分内部每个字符也需要一致
举例:aaa123aaa bbb456bbb 111789111 &&abc&&
public class regexTest {
public static void main(String[] args) {
// 需求1
// \\组号 表示把把x组内容再拿出来用一次
String regex1 = "(.).+\\1";
System.out.println("a123a".matches(regex1)); // true
System.out.println("&abc&".matches(regex1)); // true
System.out.println("b4561".matches(regex1)); // false
//需求2
String regex2 = "(.+).+\\1";
System.out.println("abc123abc".matches(regex2)); // true
System.out.println("&!@abc&!@".matches(regex2)); // true
System.out.println("123789b".matches(regex2)); // false
//需求3
//某某某需要一致 需要捕获分组
// (.) 把首字母看成一组
// \\2 被首字母拿出来再次使用
// * 作用于\\1 表示后面重复的内容出现0次或者多次
String regex3 = "((.)\\2*).+\\1";
System.out.println("aaa123aaa".matches(regex3)); // true
System.out.println("&&abc&&".matches(regex3)); // true
System.out.println("111789123".matches(regex3)); // false
}
}
2. 非捕获分组
分组之后不需要再用本组数据,仅仅把数据括起来,不占组号。
符号 含义 举例 (?:正则) 获取所有 Java(?:8|11|17) (? = 正则) 获取前面部分 Java(?=8|11|17) (?! 正则) 获取不是指定内容的前面部分 Java(?!8|11|17)
public class regexTest {
public static void main(String[] args) {
//身份证号码的 简易正则表达式
//非捕获分组:仅仅是把数据概括起来
//特点:不占用组号
// (?:) (?=) (?!)
//更多使用第一个
String regex = "[1-9]\\d{16}(?:\\d|x|x)\\1";
String regex1 = "[1-9]\\d{16}(\\d|x|x)\\1";
System.out.println("41080119930228457x".matches(regex));
}
}