11.16.1 认识正则表达式
使用正则表达式可以方便地对数据进行匹配,还可以执行更加复杂的字符串验证、拆分、替换功能。
Java对正则表达式操作的类是需要通过Pattern和Matcher两个类完成!!!正则表示是在JDK1.4之后引入到Java之中的。
11.16.2 Pattern类和Matcher类
如果要在程序中应用正则表达式则必须依靠Pattern类和Matcher类,这两个类都在java.util.regex包中定义。
- Pattern类的抓哟作用是进行正则规范的编写
- Matcher类主要是执行规范,验证一个字符串是否符合规范
补充:正则表达式的基础知识:更多字符含义请戳这里!!!
- 句点符号 . ------>> 句点符号匹配所有字符,包括空格、Tab字符甚至换行符
- 方括号符号 [] ------>> 为解决句点符号匹配范围过于广泛的问题,可以在方括号[] 里面指定有意义的字符。 此时只有方括号里面指定的字符才参与匹配。 也就是说,正则表达式“t[aeio]n”只匹配“tan”、“ten”、“tin”、“ton”。 但是“toon”不匹配,因为在方括号中你只能匹配单个字符!!!
- “或”符号 | ----->> 如果除了上面匹配的所有单词之外,你还想匹配“toon”,那么,可以使用 “ | ” 操作符。 “ | ”操作符的基本意义就是“或”运算。 要匹配“toon”,使用“t(a|e|i|o|oo)n”正则表达式。这里不能使用方括号,因为方括号只允许匹配单个字符; 这里必须使用圆括号“ () ”。 圆括号还可以用来分组。
- “否”符号 ^ ----->> " ^ "符号称为“否”符号。如果用在方括号内。 “ ^ ”表示不想要匹配的字符。例如[^abc]表示除了a、b、c之外的任意字符
- 圆括号和空白符号 ---->> " /s "符号是空白符号,匹配所有的空白字符,包括Tab字符。 如果字符串正确匹配,接下来如何提取出月份部分呢??只需要在月份周围加上一个圆括号创建一个组~~
- 其他字符 -----> \t: 制表符,等同于/u0009; \n:换行符,等同于/u000A; \d:代表一个数组,等同于[0-9]; \D:代表非数字,等同于[^0-9]; \s:代表换行符、Tab制表符等空白字符; \S:代表非空白字符; \w: 字母、数字、下划线字符,等同于[a-zA-z_0-9]; \W:非字母字符,等同于[^/w]
- 表示匹配次数的符号, 见下表
元字符 | 说明 |
. | 匹配任何单个字符(不能匹配多个字符) |
$ | 匹配行结束符。例如,“EJB$”,能匹配“I like EJB”,但是不能匹配“J2EE without EJBs!” |
^ | 匹配一行的开始。 |
* | 匹配0至多个在它之前的字符。例如“zo*”能够匹配 zoo,zoooo |
\ | 转义符,用来将元字符当作普通的字符来匹配。 |
[] | 匹配括号中的任何一个字符;可以在括号中使用连字符“-”来指定字符的区间来简化表示; 还可以指定多个区间。还有一个相配合使用的元字符“^“进行”排除“。 |
() | 将()之间括起来的表示是定义为”组“ group, 并且将匹配这个表达式的字符保存到一个临时区域,这个元字符在字符串提取的时候非常有用 |
| | 将两个匹配条件进行逻辑”或“运算。 |
+ | 匹配前面的子表达式一次或多次。 |
? | 匹配前面的子表达式0次或一次;另外也表示非贪婪模式匹配 |
{n} | 匹配确定的n次 |
{n,} | 至少匹配n次 |
{n,m} | 最少匹配n次且最多匹配m次。 |
在Pattern类中使用一些正则规则即可完成相应的操作。Pattern类常用的方法有:
public static Pattern compile(String regex) //指定正则表达式规则
public Matcher matcher(CharSequence input) //返回Matcher类实例
public String[] split(CharSequence input) //字符串拆分
***********************在Pattern类中如果要去的Pattern类实例,则必须调用compile()方法!!!************************************
如果要验证一个字符串是否符合规范,则可以使用Matcher类。 Matcher类的常用方法有:
public boolean matches() //执行验证
public String replaceAll(String replacement) //字符串替换
下面直接使用Pattern类和Matcher类完成一个简单的验证过程。
(1)日期格式要求: yyyy-MM-dd
(2)正则表达式如下: \d{4} - \d{2} - \d{2}
范例:验证一个字符串是否是合法的日期格式:
package ort.forfan06.regexdemo;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexDemo01{
public static void main(String args[]){
String str = "1985-09-18";
String pat = "\\d{4}-\\d{2}-\\d{2}"; //定义验证规则,需要用到转义字符将“\d”中的“\”转义成字符。
Pattern p = Pattern.compile(pat); //实例化Pattern类对象
Matcher m = p.matcher(str); //验证字符串内容是否合法
if(m.matches()){ //使用正则验证
System.out.println("日期格式合法!");
}else{
System.out.println("日期格式不合法!");
}
}
}
范例:按照字符串的数字将字符串拆分
package ort.forfan06.regexdemo;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexDemo02{
public static void main(String args[]){
String str = "A1B22C333D4444E55555F";
String pat = "\\d+";
Pattern p = Pattern.compile(pat);
String s[] = p.split(str);
for(int i = 0; i < s.length; i++){
System.out.print(s[i] + "\t");
}
}
}
范例:将全部的数字替换成“_”
//package ort.forfan06.regexdemo;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexDemo03{
public static void main(String args[]){
String str = "A1B22C333D4444E55555F";
String pat = "\\d+";
Pattern p = Pattern.compile(pat);
Matcher m = p.matcher(str);
String newString = m.replaceAll("_");
System.out.println(newString);
}
}
11.16.3 String类对正则表达式的支持
在String类中有3个方法支持正则表达式操作。如下所示:
public boolean matches(String regex) //字符串匹配
public String replaceAll(String regex, String replacement) //字符串替换
public String[] split(String regex) //字符串拆分
范例:使用String类修改之前的操作
package ort.forfan06.regexdemo;
//import java.util.regex.Pattern;
//import java.util.regex.Matcher;
public class RegexDemo04{
public static void main(String args[]){
String str1 = "A1B22C333D4444E55555F".replaceAll("\\d+", "_");
boolean temp = "1985-09-18".matches("\\d{4}-\\d{2}-\\d{2}");
String s[] = "A1B22C333D4444E55555F".split("\\d+");
System.out.println("字符串替换操作:" + str1);
System.out.println("字符串替换验证:" + temp);
System.out.println("字符串拆分:");
for(int i = 0; i < s.length; i++){
System.out.print(s[i] + "\t");
}
}
}
- 在正则表达式操作中,如果出现了一些正则表达式中的字符,则需要对这些字符进行转义操作。
范例:现在有字符串“FORFAN:06|CSDN:05|LEYI:75”,要求将其拆分成一下形式:
FORFAN 06
CSDN 05
LEIYI 75
如果要完成以上要求,则肯定先要使用“|”拆分,之后再使用“:”拆分;如果直接使用“|”拆分会发现根本就无法正确执行
(1)使用“|”拆分
//package ort.forfan06.regexdemo;
//import java.util.regex.Pattern;
//import java.util.regex.Matcher;
public class RegexDemo05{
public static void main(String args[]){
String str1 = "FORFAN:06|CSDC:05|LEYI:75";
String s[] = str1.split("|");
for(int i = 0; i < s.length; i++){
System.out.print(s[i] + "、");
}
}
}
输出结果是:
、F、O、R、F、A、N、:、0、6、|、C、S、D、C、:、0、5、|、L、E、Y、I、:、7、5、
可以发现,字符串并没有按照预期的那样进行拆分。这是因为 “|” 在正则表达式中表示“或”的概念。 在使用时就对其进行转义操作。 写成 “\\|”, 其中"\\"表示一个"\"。。。。
(2) 对正则进行转义
//package ort.forfan06.regexdemo;
//import java.util.regex.Pattern;
//import java.util.regex.Matcher;
public class RegexDemo06{
public static void main(String args[]){
String str1 = "FORFAN:06|CSDC:05|LEYI:75";
String s[] = str1.split("\\|");
System.out.println("字符串拆分:");
for(int i = 0; i < s.length; i++){
String s2[] = s[i].split(":");
System.out.println(s2[0] + "\t" + s2[1]);
}
}
}
11.17 定时调度
11.17.1 Timer类
Timer类是一种线程设施,可以用来实现在某一个时间或某一段时间后安排某一个任务执行一次或定期重复执行。该功能要与TimerTask配合使用。TimeTask类用来实现由Timer安排的一次或重复执行的某一个任务。
每一个Timer对象对应的是一个线程,因此计时器所执行的任务应该迅速完成,否则可能会延时后续任务的执行, 而这些后续的任务就有可能堆在一起,等到该任务完成后才能快速连续执行。
Timer类中的常用方法:
public Timer() //用来创建一个计时器并启动该计时器
public void cancel() //终止该计时器,并放弃所有已安排的任务,对当前正在执行的任务没有影响
public int purge() //将所有已经取消的任务移除,一般用来释放内存空间
public void schedule(TimerTask task, Date time) //安排一个任务在指定的时间执行,如果已经超过了该时间,则立即执行
public void schedule(TimerTask task, Date firstTime, long period) //安排一个任务在指定的时间执行,然后以固定的频率(毫秒)重复执行
public void schedule(TimerTask task, long delay) //安排一个任务在一段时间(毫秒)后执行
public void schedule(TimerTask task, long delay, long period) //安排一个任务在一段时间(毫秒)后执行,然后以固定的频率(毫秒)重复执行
public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) //安排一个任务在指定的时间执行,然后以近似固定的频率(毫秒)重复执行
public void scheduleAtFixedRate(TimerTask task, long delay, long period) //安排一个任务在一段时间(毫秒)后执行,然后以近似固定的频率(毫秒)重复执行
这里要说明的是schedule()和scheduleAtFixedRate()方法的区别在于重复执行任务时,对于时间间隔出现延时的情况处理:
- schedule()方法的执行时间间隔永远是固定的!!如果之前出现了延时情况,之后也会继续按照设定好的间隔时间来执行。
- scheduleAtFixedRate()方法可以根据出现的延时时间自动调整下一次间隔的执行时间!!
11.17.2 TimerTask类
要执行具体的任务,则必须使用TimerTask类。TimerTask类是一个抽象类,如果要使用该类,需要自己建立一个类来继承此类,并实现其中的抽象方法。 TimerTask类中的常用方法:
public void cancel() //终止此任务。如果该任务只执行一次且未执行,则永远不会再执行;如果为重复任务,则之后不会再执行(正在执行中,则执行完后不会执行)
public void run() //该任务所要执行的具体操作,该方法为引入的接口Runnable中的方法,子类需要覆写此方法
public long scheduledExecutionTime() //返回最近一次执行该任务的时间(若正在执行,则返回此任务的执行安排时间),一般在run()方法中调用。判断当前是否有足够的时间执行该任务
11.17.3 范例 --- 定时操作
范例:定时打印系统的当前时间:
//package ort.forfan06.timertaskdemo;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
import java.util.Timer;
class MyTask extends TimerTask{
public void run(){
SimpleDateFormat sdf = null;
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println("当前系统时间为:" + sdf.format(new Date()));
}
}
public class TimerTaskDemo01{
public static void main(String args[]){
Timer t = new Timer();
MyTask mytask = new MyTask();
t.schedule(mytask, 1000, 2000);
}
}
11.18 本章要点
- 在一个字符串内容需要频繁修改时,使用StringBuffer类可以提升操作性能!因为StringBuffer类的对象内容是可以改变的,而String内容则不可以改变。
- StringBuffer类中提供了大量的字符串操作方法, 如增加、替换、插入等等
- Runtime表示运行时,在一个JVM中只存在一个Runtime,所以如果想要取得Runtime类的对象,直接使用Runtime类中提供的静态方法getRuntime()方法即可。
- 国际化程序实现的基本原理为:所有的语言信息以key --> value的形式保存在资源文件(.properties)之中,程序通过key找到相应的value,根据其所设置的国家的Locale对象不同,找到资源文件也不同。要想实现国际化必须依靠Locale、ResourceBundle两个类共同完成
- System类是系统类,可以取得系统的相关信息,使用System.gc()方法中可以强制性地进行垃圾的收集操作,调用此方法实际上就是调用了Runtime类中的gc()方法
- Format类为格式化操作类,主要的3个子类是MessageFormat、DateFormat、NumberFormat。
- 使用Date类可以方便地取得时间,但取得的时间格式不符合地域的风格;所以可以使用SimpleDateFormat类进行日期的格式化操作
- 处理大数字可以使用BigInteger和BigDecimal类。当需要精确小数点操作位数时,应使用BigDecimal类
- 通过Random类可以取得指定范围的随机数字
- 如果一个类的对象要被克隆。则此对象所在的类必须实现Cloneable接口
- 要对一组对象进行排序,则必须使用比较器。比较器接口Comparable中定义了compareTo()的比较方法,用来设置比较规则
- 正则表达式是开发中最常使用的一种验证方法,String类中的replaceAll()、split()、matches()方法都对正则表达式有所支持
- 可以使用Timer和TimerTask类完成系统的定时操作
11.19 习题
- 定义一个StringBuffer类对象,然后通过append()方法向对象中添加26个小写字母,要求每次只添加一个,共添加26次。 然后按照逆序的方法输出,并且可以删除前5个字符
- 利用Random类产生5个1~30之间(包括1和30)的随机整数
- 输入一个Email地址,然后使用正则表达式验证该Email地址是否正确
- 编写程序,用0~1 之间的随机数来模拟仍硬币实验。统计仍1000次后出现正、反面的次数并输出
- 编写正则表达式,判断给定的是否是一个合法的IP地址
- 给定下面HTML代码 <font face="Arial,Serif" size="+2" color="red">要求对内容进行拆分,拆分之后结果:face Arial,Serif size +2 color red
- 编写程序,实现国际化应用,从命令行输入国家的代号,例如,1表示中国,2表示美国,然后根据输入代号的不同调用不同的资源文件显示信息
- 按照“姓名:年龄:成绩|姓名:年龄:成绩”的格式定义字符串“张三 21:98|李四:22:89|王屋:20:70”,要求将每组值分别保存在Student对象之中,并对这些对象进行排序,排序的原则是:按照成绩由高到低,如果成绩相等,则按照年龄由低到高排序