实验10 常用实用类
10.1 实验目的
- 理解String类的特性,熟练掌握String类的常用方法。
- 掌握正则表达式的使用方法。
- 能用日期类创建对象,熟练掌握日期类的常用方法。
- Arrays类的常用方法使用。
10.2 实验内容
10.2.1 编写一个正则表达式,自己定义一个String类型的字符验证是否满足该正则表达式。(比如可以验证字符串是否以a开头,以b结尾的字符串,其正则表达式为:regx=a.*b)
【前提引入】
1️⃣ 字符匹配符 —— “ . ”
符号 | 名称 | 示例 | 解释 |
. | 匹配出\n以外的任何字符 | a…b | 以a开头,b结尾,中间包括2个任意字符的长度为4的字符串 |
[] | 可接收的字符列表 | [efgh] | 是 e、f、g、h 中的任意一个字符 |
2️⃣ 选择匹配符 —— " * "
符号 | 名称 | 示例 | 解释 |
* | 指定字符重复0次或多次 | (abc)* | 仅包含任意个 abc 的字符串出现0或多次 |
+ | 指定字符重复1次或多次 | m+abc | 以至少一个m开头后接abc |
3️⃣ 定位符
符号 | 名称 | 示例 | 解释 |
^ | 指定起始开始字符 | ^a+[a-z]$ | 以至少一个a开头,后接任意个小写字母的字符串 |
$ | 指定结束字符 | ^[0-9]+c$ | 以至少一个数字开头,后接字母c结尾的字符串 |
📍 那怎样写以 a 开头,以 b 结尾的字符串呢?
- 以a开头:
^a
- 以b结尾:
b$
- 中间字符串任意对应
.
,有或没有都可以 对应*
,因此组合起来是:.*
所以组合起来就是:^a.*b$
3️⃣ String类中具有判断功能的 matches 方法
解读:public boolean matches(String regex)
该方法是进行整体匹配,相当自带 ^ 和 $
既然自带了,那么以a开头,以b结尾的字符串就可以由原来的 ^a.*b$
写为 a.*b
当然,如果你写的是 matches(“^a.*b$”) 这也是对的,完全等价于 matches(“a.*b”)。
【核心代码】
import java.util.Scanner; public class RegxTest { public static void main(String[] args) { //创建一个扫描器对象 Scanner scanner = new Scanner(System.in); //通过键盘输入字符串 String str = scanner.next(); //进行正则匹配,调用 matches 方法 if(str.matches("a.*b")){ System.out.println("匹配成功"); }else{ System.out.println("匹配失败"); } } }
【运行流程】
10.2.2 利用Pattern类和Matcher类以及其类中的方法,统计字符串str1,在str2中出现的次数。
【前提引入】
1️⃣ Pattern类
Pattern类对象是一个正则表达式对象。Pattern类没有公共的构造的方法:
因此要创建一个 Pattern 类对象,需要调用其公共的静态方法compile
,它会返回一个Pattern对象。该方法接收一个正则表达式作为它的第一个参数,看下该方法的源码:
/** * Compiles the given regular expression into a pattern. * * @param regex * The expression to be compiled * @return the given regular expression compiled into a pattern * @throws PatternSyntaxException * If the expression's syntax is invalid */ public static Pattern compile(String regex) { return new Pattern(regex, 0); }
2️⃣ Matcher类
Matcher类对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共的构造方法,需要调用Pattern对象的matcher方法来获得一个Matcher对象。
/* input:要匹配的字符序列 */ public Matcher matcher(CharSequence input) { if (!compiled) { synchronized(this) { if (!compiled) compile(); } } Matcher m = new Matcher(this, input); return m; }
📍 一个常用方法:
public boolean find():部分匹配,找到一个匹配的子串,则返回true,并将定位移动到下次匹配的位置。
【核心代码】
public class RegxTest { public static void main(String[] args) { //已知字符串 String str2 = "abc.defabc.kabc"; //创建一个扫描器对象 Scanner scanner = new Scanner(System.in); //通过键盘输入字符串 String str1 = scanner.next(); //创建Pattern类对象,参数是正则表达式规则 Pattern pattern = Pattern.compile(str1); //对输入字符串 str2 依照 str1 正则表达式规则进行解释和匹配的引擎 Matcher matcher = pattern.matcher(str2); //用于统计出现次数 int count = 0; //find方法:部分匹配,找到一个匹配的子串,则返回true,并将定位移动到下次匹配的位置。 while (matcher.find()) { count++; } System.out.println("出现次数:" + count); } }
【运行流程】
10.2.3 编写一个计算纪念日提醒的Java程序,具有倒计时功能,以及到期提醒功能(如离某某人生日还有多少天,今天是某某人生日),以及距离某一个日期已经多少天,多少小时等(如已经进入中南林业科技大学2年X月X天,注意:最少精确到天)。
【前提引入】
所在类 | 是否静态方法 | 方法 | 返回值 | 含义 |
LocalDate | 静态 | now() | LocalDate | 获取当前时间LocalDate对象,包括年月日 |
LocalDate | 静态 | getYear() | int | 获取对象的年份 |
LocalDate | 静态 | parse(String dateStr) | LocalDate | 将一个日期字符串dateStr解析转为LocalDate对象 |
LocalDate | 非静态 | isBefore(LocalDate localDate) | boolean | 判断对象时间是否在localDate时间之前 |
LocalDate | 非静态 | isAfter(LocalDate localDate) | boolean | 判断对象时间是否在localDate时间之后 |
LocalDate | 非静态 | until(LocalDate localDate,ChronoUnit.DAYS) | long | 返回locaDate与对象天数差 |
LocalDate | 静态 | Period.between(start, end) | Period | 两个时间相差的年月日Period对象 |
Period | 非静态 | getYears | int | period对象存储的年份 |
Period | 非静态 | getMonths | int | period对象存储的月份 |
Period | 非静态 | getDays | int | period对象存储的天数 |
【核心代码】
import java.time.LocalDate; import java.time.Period; import java.time.temporal.ChronoUnit; public class DateTest { public static void main(String[] args) { //得到当前时间(年月日) LocalDate now = LocalDate.now(); //定义某人生日时间 String birthday = "11-05"; //获取当前年份 int nowYear = now.getYear(); //获取今年的生日时间 LocalDate birthdayDate1 = LocalDate.parse(nowYear + "-" + birthday); //如果当前时间在今年生日时间之前 if (now.isBefore(birthdayDate1)) { //那么可以直接计算时间差 System.out.println("距离生日还有:" + now.until(birthdayDate1, ChronoUnit.DAYS)); } else if (now.isAfter(birthdayDate1)) { //如果当前时间在今年生日时间之后,说明生日已过,那么计算距离明年生日的天数 //获取明年的生日时间 LocalDate birthdayDate2 = LocalDate.parse(nowYear + 1 + "-" + birthday); //计算天数差 System.out.println("距离生日还有:" + now.until(birthdayDate2, ChronoUnit.DAYS)); }else{ //说明恰好是今天 System.out.println("今天是雨浪的生日"); } System.out.println("-------------------------------------------------------"); //定义进校时间 LocalDate intoSchoolDate = LocalDate.parse("2021-09-10"); //得到现在与进校时间的时间差:年、月、日 Period period = Period.between(intoSchoolDate, now); //输出时间差 System.out.println("现在与进校时间相差:" + period.getYears() + " 年 " + period.getMonths() + " 月 " + period.getDays() + " 日"); } }
【运行流程】
10.2.4 新建一个Student类,属性为姓名,年龄,学号,声明一个Student的对象数组,分别按照年龄和学号进行排序并输出结果。
【前提引入】
Arrays类
:包含了一系列的静态方法,用于管理或操作数组(比如排序和搜索)
Arrays.sort方法
:因为数组是引用类型,所以通过 sort 排序后会直接影响到数组本身。sort是重载的,也可以通过传入一个接口 Comparator 实现定制排序规则,调用定制排序时,传入两个参数:
- 排序的数组arr
- 实现了Comparator接口的匿名内部类,要求重写compare方法,通过返回值的正负情况决定了排序规则。
这充分体现了 接口编程 + 动态绑定 + 匿名内部类 的综合使用。
📍 这里我们通过一个简单模拟来该方法的实现(对于理解Arrays的sort方法很重要):
public class ArraysTest { /** * 使用 冒泡排序 + 匿名内部类 来简单模拟 Arrays.sort 方法的实现 * 也就是说,我们在这里自定义一个sort方法 * * @param arr 待排序的数组 * @param c 实现Comparator接口的类 对象 */ public static void sort(int[] arr, Comparator c) { int temp = 0; for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - 1 - i; j++) { //数组排序由 c.compare(arr[j], arr[j + 1])返回的值决定 //如果返回正数则进行交换,否则不交换 if (c.compare(arr[j], arr[j + 1]) > 0) { temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } public static void main(String[] args) { int[] arr = {5,3,2,8,7}; //从小到大排序 sort(arr,new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { //value1 代表 arr[j] 的值 int value1 = (Integer)o1; //value2 代表 arr[j+1] 的值 int value2 = (Integer)o2; //如果返回正数,即arr[j]比arr[j+1]大时,在sort方法中会将这两个位置上的值进行交换 //则说明了我们指定的是从小到大进行排序 return value1-value2; } }); //使用 Arrays.toString方法 打印数组 System.out.println(Arrays.toString(arr)); } }
【核心代码】
- Student类(为了演示方便,这里把属性的修饰符定为 public )
package com.csuft; public class Student { public String name; public int age; public int studentId; public Student(String name, int age, int studentId) { this.name = name; this.age = age; this.studentId = studentId; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", studentId=" + studentId + '}'; }
- ArraysTest类
import java.util.Arrays; import java.util.Comparator; public class ArraysTest { public static void main(String[] args) { Student[] students = new Student[] { new Student("雨浪",18,20212819), new Student("夜莺",16,20212850), new Student("狐狸半面添",17,20212880) }; System.out.println("-------------依照年龄对数组进行 升序 排序------------"); Arrays.sort(students, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.age-o2.age; } }); for (Student student : students) { System.out.println(student); } System.out.println("-------------依照学号对数组进行 降序 排序------------"); Arrays.sort(students, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o2.studentId-o1.studentId; } }); for (Student student : students) { System.out.println(student); } } }
【运行流程】