Lab3因而起——对正则表达式的学习(二)
一、Pattern和Matcher
一般来讲,比起String类,正则表达式的功能更为强大。对于正则表达式,可以通过java自带的包java.util.regax,将其导入之后,运用方法Pattern.compile()来编译创造的正则表达式。这个方法会根据输入的String类型的正则表达式生成一个Pattern对象,接下来,把想要检索的字符换传入Pattern对象的matcher方法,又会生成一个matcher对象,这个对象有很多功能。
其中,replaceAll()方法能将所有匹配的部分都替换成传入的参数;
boolean matches()
boolean lookingAt()
boolean find()
boolean find(int start)
其中,matches()方法是用来判断整个输入的字符串是否匹配表达式模式的,而lookingAt()是用来判断该字符串的开始部分是否能够匹配模式。find()方法可以用来在charSequence中查找多个匹配,像迭代器那样向前遍历输入字符串,且find()能够接受一个整数作为参数,该整数表示字符串中字符的位置,并以其作为搜索的起点。
例如:
import java.util.regex.*;
public class boke {
public static void main(String[] args) {
Matcher m = Pattern.compile("\\w+").matcher("Evening is full of the linnet's wings");
while(m.find()) {
System.out.print(m.group()+" ");
}
System.out.println();
for(int i = 0;m.find(i);i++) {
System.out.print(m.group()+" ");
}
}
}
得到输出:
需要注意的是,find()可以在输入的任意位置定位正则表达式,而lookingAt()和matches()只有在正则表达式与输入的最凯斯处就开始匹配时才会成功。Matches()只有在输入都匹配正则表达式的时候才会成功,而lookingAt()只要输入的第一部分匹配就会成功。
除此外,Pattern类的compile()方法还有另一个版本,它接受一个标记参数,从而调整匹配的行为:
Pattern Pattern.compile(String regex,int flag)
其中flag来自以下常量:
Patern.CANON_EQ :两个字符当且仅当他们的完全规范分解相匹配时,就认为他们是匹配的。
Pattern.CASE_INSENSITIVE(?i):默认情况下,大小写不敏感的匹配假定只有US-ASCII字符级中的字符才能进行,这个标记允许匹配模式不必考虑大小写。
Pattern.COMMENTS(?x):在这种模式下,空格符将被忽略掉,并且以#开始直到行末的指数也会被忽略掉,通过嵌入的标记表达式也可以开启Unix的模式。
Pattern.DOTALL(?s):在dotall模式下,表达式‘.’匹配素有字符,包括行终结符。默认情况下,‘.’表达式不必配行终结符。
Pattern.MULTILINE(?m):在多行模式下,表达爱是^和 分 别 匹 配 一 行 的 开 始 与 结 束 。 还 匹 配 输 入 字 符 串 的 开 始 , 分别匹配一行的开始与结束。^还匹配输入字符串的开始, 分别匹配一行的开始与结束。还匹配输入字符串的开始,还匹配输入字符换的结尾。
Psttrtn.UNICODE_CASE(?u):当指定这个标记,并且开始CASE_INSENSITIVE时,大小写不敏感将按照与Unicode标准一致的方式进行。
Pattern.UNIX_LINES(?d):在这种模式下,在.、^和$行为种,只识别行终结符‘\n’
二、组
组:用括号划分的正则表达式,可以根据组的编号来引用某个组。组号为0表示整个表达式,组号为1表示最外层括号括起来的组,例:
Absahduaid(sjawodjojxm(xajaodjwid)sjaidjoa)sjaoiwdnnmmjaijx
在这个正则表达式中,组号为0的就是Absahduaid(sjawodjojxm(xajaodjwid)sjaidjoa)sjaoiwdnnmmjaijx,组号为1的就是sjawodjojxm(xajaodjwid)sjaidjoa,组号为2的就是xajaodjwid。
Matcher对象为了获取组的信息,为此专门提供了一系列的方法:
public int groupCount():返回该匹配器模式中的分组数目;
Public String group():返回前一次匹配操作。
三、split()方法
不同于String,正则表达式也有关于split函数的应用,split()方法将输入字符串断开成字符串对象数组,断开边界有下列正则表达式确定:
String[] split(CharSequence input);
String[] split(CharSequence input,int limit);
接下来我用代码展示函数的作用:
import java.util.*;
import java.util.regex.*;
public class boke {
public static void main(String[] args) {
String input =
"He , who is a student,likes to study!";
System.out.println
(Arrays.toString(Pattern.compile(",").split(input)));
System.out.println
(Arrays.toString(Pattern.compile(",").split(input,2)));
}
}
有关运行结果:
第一种方式是将input以‘,’隔开,分成数量位置的字符串数组。
而第二种方式是将input以‘,’隔开并分为固定几组,从前往后,当组数足够使便不再分割。
由上图可以观察到,通过对‘,’的分割将input分割成为了三个字符串并输出,而第二行输出是固定的通过‘,’从前往后将input分割为了两哥字符串停止后并输出。
四、替换操作
正则表达式特别方便于替换文本,因此提供了许多方法:
replaceFirst(String replacement):以参数字符串replacement替换掉第一个匹配成功的部分。
replaceAll(String replacement):以参数字符串replacement替换掉所有匹配成功的部分。
appendReplacement(StringBuffer sbuf,String replacement):执行渐进性的替换,这个方法允许调用其它方法来生成或处理repalcement,使能够以编程的方式将目标分割成组,从而具备更强大的功能。而方法appendTail(StringBUffer sbuf),在执行了一次或者多次appendReplacement()之后,可以通过调用这个方法将输入的字符串余下的部分复制到subf中。
在这里就不过多的用代码来举例了。
五、reset方法
通过reset方法,可以对现有的Matcher对象应用于一个新的字符序列。
用代码进行实例:
import java.util.regex.*;
public class boke {
public static void main(String[] args) {
Matcher m = Pattern.compile("[frb][aiu][gx]").matcher("fix the rug with bags");
while(m.find()) {
System.out.print(m.group()+" ");
}
System.out.println();
m.reset("fix the rig with bags");
while(m.find()) {
System.out.print(m.group()+" ");
}
}
}
输出结果为:
六、lab3实例
static void readFile(String strFile) throws Exception{
BufferedReader bReader = new BufferedReader(new FileReader(new File(strFile)));
String line="";
int count = 0;
StringBuilder stringInfo = new StringBuilder("");
while((line = bReader.readLine()) != null) {
if((line.equals("")))
continue;
stringInfo.append(line+"\n");
count++;
if(count % 13 == 0) {
Pattern pattern = Pattern.compile("Flight:(([0-9]{4})-((0[1-9])|(1[0-2]))-((3[0-1])|([1-2][0-9])|(0[1-9]))),([A-Z]{2}[0-9]{2}[0-9]?[0-9]?)\n\\{\nDepartureAirport:([A-Z][a-z]*)\nArrivalAirport:([A-Z][a-z]*)\nDepatureTime:(([0-9]{4})-((0[1-9])|(1[0-2]))-((3[0-1])|([1-2][0-9])|(0[1-9])) ((2[0-4]|([0-1][0-9])):[0-5][0-9]))\nArrivalTime:(([0-9]{4})-((0[1-9])|(1[0-2]))-((3[0-1])|([1-2][0-9])|(0[1-9])) ((2[0-4]|([0-1][0-9])):[0-5][0-9]))\nPlane:((B|N)[0-9]{4})\n\\{\nType:([a-z]|([A-Z])([0-9]+))\nSeats:((600)|([1-5][0-9]{2})|([5-9][0-9]))\nAge:((([0-9])(\\.[0-9])?)|(([1-2][0-9])(\\.[0-9])?)|(30(\\.0)?)|)\n\\}\n\\}\n");
Matcher matcher = pattern.matcher(stringInfo.toString());
if(matcher.matches()) {
String name = matcher.group(10);
String num = matcher.group(37);
String type = matcher.group(39);
String seats = matcher.group(42);
String year = matcher.group(46);
String start = matcher.group(11);
String end = matcher.group(12);
String leatime = matcher.group(13);
String arrtime = matcher.group(25);
Location l1 = new Location(start,0,0,true);
Location l2 = new Location(end,0,0,true);
List<Location> loc = new ArrayList<Location>();
loc.add(l1);
loc.add(l2);
MultipleLocationEntryImpl mle = new MultipleLocationEntryImpl(loc);
Timeslot t1 = new Timeslot(leatime,arrtime);
List<Timeslot> time = new ArrayList<Timeslot>();
time.add(t1);
BlockableEntryImpl be = new BlockableEntryImpl(time,1);
Flight f = new Flight(num,type,Integer.valueOf(seats),Double.valueOf(year));
List<Flight> f0 = new ArrayList<Flight>();
f0.add(f);
MultipleSortedResourceEntryImpl<Flight> msre =new MultipleSortedResourceEntryImpl<Flight>(f0);
FlightEntry<Flight> flight = new FlightEntry<Flight>(new Allocated(),name,mle,be,msre);
addEntry(flight);
stringInfo = new StringBuilder("");
}
else
System.out.println("文件内容不合法,请重新输入:");
}
}
bReader.close();
}
首先,创建一个Pattern对象,其对应正则表达式匹配为在第一次学习中分析得到的正则表达式合在一起的形式。而后用本次讲解的Pattern.matcher生成一个Matcher对象,从而对其用matches检查读入是否匹配,并且用方法Matcher.group()对Matcher对象进行读入,并把它分配给我本来想要的各个数据,从而进行跟多的操作。