正则表达式详细讲解Word格式文档下载.docx
《正则表达式详细讲解Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《正则表达式详细讲解Word格式文档下载.docx(47页珍藏版)》请在冰豆网上搜索。
第一步,创建一个pattern对象来匹配上面的子字符串。
一旦程序运行后,如果需要的话,可以让这个对象一般化。
匹配上面格式的正则表达可以这样构成:
(/d{3})/s/d{3}-/d{4},其中/d单字符类型用来匹配从0到9的任何数字,另外{3}重复符号,是个简便的记号,用来表示有3个连续的数字位,也等效于(/d/d/d)。
/s也另外一个比较有用的单字符类型,用来匹配空格,比如Space键,tab键和换行符。
是不是很简单?
但是,如果把这个正则表达式的模式用在java程序中,还要做两件事。
对java的解释器来说,在反斜线字符(/)前的字符有特殊的含义。
在java中,与regex有关的包,并不都能理解和识别反斜线字符(/),尽管可以试试看。
但为避免这一点,即为了让反斜线字符(/)在模式对象中被完全地传递,应该用双反斜线字符(/)。
此外圆括号在正则表达中两层含义,如果想让它解释为字面上意思(即圆括号),也需要在它前面用双反斜线字符(/)。
也就是像下面的一样:
//(//d{3}//)//s//d{3}-//d{4}
现在介绍怎样在java代码中实现刚才所讲的正则表达式。
要记住的事,在用正则表达式的包时,在你所定义的类前需要包含该包,也就是这样的一行:
importjava.util.regex.*;
下面的一段代码实现的功能是,从一个文本文件逐行读入,并逐行搜索电话号码数字,一旦找到所匹配的,然后输出在控制台。
BufferedReaderin;
Patternpattern=Ppile("
//(//d{3}//)//s//d{3}-//d{4}"
);
in=newBufferedReader(newFileReader("
phone"
));
Strings;
while((s=in.readLine())!
=null)
{
Matchermatcher=pattern.matcher(s);
if(matcher.find())
System.out.println(matcher.group());
}
in.close();
对那些熟悉用Python或Javascript来实现正则表达式的人来说,这段代码很平常。
在Python和Javascript这些语言中,或者其他的语言,这些正则表达式一旦明确地编译过后,你想用到哪里都可以。
与Perl的单步匹配相比,看起来多多做了些工作,但这并不很费事。
find()方法,就像你所想象的,用来搜索与正则表达式相匹配的任何目标字符串,group()方法,用来返回包含了所匹配文本的字符串。
应注意的是,上面的代码,仅用在每行只能含有一个匹配的电话号码数字字符串时。
可以肯定的说,java的正则表达式包能用在一行含有多个匹配目标时的搜索。
本文的原意在于举一些简单的例子来激起读者进一步去学习java自带的正则表达式包,所以对此就没有进行深入的探讨。
这相当漂亮吧!
但是很遗憾的是,这仅是个电话号码匹配器。
很明显,还有两点可以改进。
如果在电话号码的开头,即区位号和本地号码之间可能会有空格。
我们也可匹配这些情况,则通过在正则表达式中加入/s?
来实现,其中?
元字符表示在模式可能有0或1个空格符。
第二点是,在本地号码位的前三位和后四位数字间有可能是空格符,而不是连字号,更有胜者,或根本就没有分隔符,就是7位数字连在一起。
对这几种情况,我们可以用(-|)?
来解决。
这个结构的正则表达式就是转换器,它能匹配上面所说的几种情况。
在()能含有管道符|时,它能匹配是否含有空格符或连字符,而尾部的?
元字符表示是否根本没有分隔符的情况。
最后,区位号也可能没有包含在圆括号内,对此可以简单地在圆括号后附上?
元字符,但这不是一个很好的解决方法。
因为它也包含了不配对的圆括号,比如"
(555"
或"
555)"
。
相反,我们可以通过另一种转换器来强迫让电话号码是否带有有圆括号:
(/(/d{3}/)|/d{3})。
如果我们把上面代码中的正则表达式用这些改进后的来替换的话,上面的代码就成了一个非常有用的电话号码数字匹配器:
Patternpattern=
Ppile("
(//(//d{3}//)|//d{3})//s?
//d{3}(-|)?
//d{4}"
可以确定的是,你可以自己试着进一步改进上面的代码。
现在看看第二个例子,它是从Friedl的中改编过来的。
其功能是用来检查文本文件中是否有重复的单词,这在印刷排版中会经常遇到,同样也是个语法检查器的问题。
匹配单词,像其他的一样,也可以通过好几种的正则表达式来完成。
可能最直接的是/b/w+/b,其优点在于只需用少量的regex元字符。
其中/w元字符用来匹配从字母a到u的任何字符。
+元字符表示匹配匹配一次或多次字符,/b元字符是用来说明匹配单词的边界,它可以是空格或任何一种不同的标点符号(包括逗号,句号等)。
现在,我们怎样来检查一个给定的单词是否被重复了三次?
为完成这个任务,需充分利用正则表达式中的所熟知的向后扫描。
如前面提到的,圆括号在正则表达式中有几种不同的用法,一个就是能提供组合类型,组合类型用来保存所匹配的结果或部分匹配的结果(以便后面能用到),即使遇到有相同的模式。
在同样的正则表达中,可能(也通常期望)不止有一个组合类型。
在第n个组合类型中匹配结果可以通过向后扫描来获取到。
向后扫描使得搜索重复的单词非常简单:
/b(/w+)/s+/1/b。
圆括号形成了一个组合类型,在这个正则表示中它是第一组合类型(也是仅有的一个)。
向后扫描/1,指的是任何被/w+所匹配的单词。
我们的正则表达式因此能匹配这样的单词,它有一个或多个空格符,后面还跟有一个与此相同的单词。
注意的是,尾部的定位类型(/b)必不可少,它可以防止发生错误。
如果我们想匹配"
Parisinthethespring"
,而不是匹配"
Java'
sregexpackageisthethemeofthisarticle"
根据java现在的格式,则上面的正则表达式就是:
Patternpattern=Ppile("
//b(//w+)//s+//1//b"
最后进一步的修改是让我们的匹配器对大小写敏感。
比如,下面的情况:
"
ThethethemeofthisarticleistheJava'
sregexpackage."
,这一点在regex中能非常简单地实现,即通过使用在Pattern类中预定义的静态标志CASE_INSENSITIVE:
Patternpattern=Ppile("
Pattern.CASE_INSENSITIVE);
有关正则表达式的话题是非常丰富,而且复杂的,用Java来实现也非常广泛,则需要对regex包进行的彻底研究,我们在这里所讲的只是冰山一角。
即使你对正则表达式比较陌生,使用regex包后会很快发现它强大功能和可伸缩性。
如果你是个来自Perl或其他语言王国的老练的正则表达式的黑客,使用过regex包后,你将会安心地投入到java的世界,而放弃其他的工具,并把java的regex包看成是手边必备的利器。
CharSequence
JDK1.4定义了一个新的接口,叫CharSequence。
它提供了String和StringBuffer这两个类的字符序列的抽象:
interfaceCharSequence{
charAt(inti);
length();
subSequence(intstart,intend);
toString();
}
为了实现这个新的CharSequence接口,String,StringBuffer以及CharBuffer都作了修改。
很多正则表达式的操作都要拿CharSequence作参数。
Pattern和Matcher
先给一个例子。
下面这段程序可以测试正则表达式是否匹配字符串。
第一个参数是要匹配的字符串,后面是正则表达式。
正则表达式可以有多个。
在Unix/Linux环境下,命令行下的正则表达式还必须用引号。
//:
c12:
TestRegularExpression.java
//Allowsyoutoeaslytryoutregularexpressions.
//{Args:
abcabcabcdefabc"
abc+"
"
(abc)+"
(abc){2,}"
}
importjava.util.regex.*;
publicclassTestRegularExpression{
publicstaticvoidmain(String[]args){
if(args.length<
2){
System.out.println("
Usage:
/n"
+
javaTestRegularExpression"
characterSequenceregularExpression+"
System.exit(0);
Input:
/"
+args[0]+"
/"
for(inti=1;
i<
args.length;
i++){
System.out.println(
Regularexpression:
+args[i]+"
Patternp=Ppile(args[i]);
Matcherm=p.matcher(args[0]);
while(m.find()){
Match/"
+m.group()+
atpositions"
m.start()+"
-"
+(m.end()-1));
}///:
~
Java的正则表达式是由java.util.regex的Pattern和Matcher类实现的。
Pattern对象表示经编译的正则表达式。
静态的compile()方法负责将表示正则表达式的字符串编译成Pattern对象。
正如上述例程所示的,只要给Pattern的matcher()方法送一个字符串就能获取一个Matcher对象。
此外,Pattern还有一个能快速判断能否在input里面找到regex的
staticbooleanmatches(?
regex,?
input)
以及能返回String数组的split()方法,它能用regex把字符串分割开来。
只要给Pattern.matcher()方法传一个字符串就能获得Matcher对象了。
接下来就能用Matcher的方法来查询匹配的结果了。
booleanmatches()
booleanlookingAt()
booleanfind()
booleanfind(intstart)
matches()的前提是Pattern匹配整个字符串,而lookingAt()的意思是Pattern匹配字符串的开头。
find()
Matcher.find()的功能是发现CharSequence里的,与pattern相匹配的多个字符序列。
例如:
FindDemo.java
importcom.bruceeckel.simpletest.*;
importjava.util.*;
publicclassFindDemo{
privatestaticTestmonitor=newTest();
Matcherm=Ppile("
//w+"
)
.matcher("
Eveningisfullofthelinnet'
swings"
while(m.find())
System.out.println(m.group());
inti=0;
while(m.find(i)){
System.out.print(m.group()+"
i++;
monitor.expect(newString[]{
Evening"
is"
full"
of"
the"
linnet"
s"
wings"
Eveningveningeningningingnggisissfull"
fullulllllofoffthetheheelinnetlinnet"
innetnnetnetettsswingswingsingsngsgss"
});
的意思是"
一个或多个单词字符"
,因此它会将字符串直接分解成单词。
find()像一个迭代器,从头到尾扫描一遍字符串。
第二个find()是带int参数的,正如你所看到的,它会告诉方法从哪里开始找——即从参数位置开始查找。
Groups
Group是指里用括号括起来的,能被后面的表达式调用的正则表达式。
Group0表示整个表达式,group1表示第一个被括起来的group,以此类推。
所以;
A(B(C))D
里面有三个group:
group0是ABCD,group1是BC,group2是C。
你可以用下述Matcher方法来使用group:
publicintgroupCount()返回matcher对象中的group的数目。
不包括group0。
publicStringgroup()返回上次匹配操作(比方说find())的group0(整个匹配)
publicStringgroup(inti)返回上次匹配操作的某个group。
如果匹配成功,但是没能找到group,则返回null。
publicintstart(intgroup)返回上次匹配所找到的,group的开始位置。
publicintend(intgroup)返回上次匹配所找到的,group的结束位置,最后一个字符的下标加一。
Groups.java
publicclassGroups{
staticpublicfinalStringpoem=
Twasbrillig,andtheslithytoves/n"
Didgyreandgimbleinthewabe./n"
Allmimsyweretheborogoves,/n"
Andthemomerathsoutgrabe./n/n"
BewaretheJabberwock,myson,/n"
Thejawsthatbite,theclawsthatcatch./n"
BewaretheJubjubbird,andshun/n"
ThefrumiousBandersnatch."
;
Matcherm=
Ppile("
(?
m)(//S+)//s+((//S+)//s+(//S+))___FCKpd___6quot;
.matcher(poem);
for(intj=0;
j<
=m.groupCount();
j++)
System.out.print("
["
+m.group(j)+"
]"
System.out.println();
monitor.expect(newString[]{
[theslithytoves]"
[the][slithytoves][slithy][toves]"
[inthewabe.][in][thewabe.][the][wabe.]"
[weretheborogoves,]"
[were][theborogoves,][the][borogoves,]"
[momerathsoutgrabe.]"
[mome][rathsoutgrabe.][raths][outgrabe.]"
[Jabberwock,myson,]"
[Jabberwock,][myson,][my][son,]"
[clawsthatcatch.]"
[claws][thatcatch.][that][catch.]"
[bird,andshun][bird,][andshun][and][shun]"
[ThefrumiousBandersnatch.][The]"
[frumiousBandersnatch.][frumious][Bandersnatch.]"
这首诗是ThroughtheLookingGlass的,LewisCarroll的"
Jabberwocky"
的第一部分。
可以看到这个正则表达式里有很多用括号括起来的group,它是由任意多个连续的非空字符('
/S+'
)和任意多个连续的空格字符('
/s+'
)所组成的,其最终目的是要捕获每行的最后三个单词;
'
$'
表示一行的结尾。
但是'
通常表示整个字符串的结尾,所以这里要明确地告诉正则表达式注意换行符。
这一点是由'
m)'
标志完成的(模式标志会过一会讲解)。
start()和end()
如果匹配成功,start()会返回此次匹配的开始位置,end()会返回此次匹配的结束位置,即最后一个字符的下标加一。
如果之前的匹配不成功(或者没匹配),那么无论是调用start()还是end(),都会引发一个IllegalStateException。
下面这段程序还演示了matches()和lookingAt():
StartEnd.java
publicclassStartEnd{
String[]input=newString[]{
Javahasregularexpressionsin1.4"
regularexpressionsnowexpressinginJava"
Javarepressesoracularexpressions"
};
Pattern
p1=Ppile("
re//w*"
),
p2=Ppile("
Java.*"
for(inti=0;
input.length;
input"
+i+"
:
+input[i]);
Matcher
m1=p1.matcher(input[i]),