|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
轮性能微软曾做过一个例子,就是同一个项目用java和.net来作,结果开发周期,.net是java的一半,性能java是.net的十分之一,代码量java是.net的三倍。呵呵,这说明了什么,.net的全方位比java好。但是有的人说.net不能跨平台,这个问题我和我同学曾讨论过,都认为微软的.net很可能早都可以跨平台了,但是微软为了保护他们的操作系统,所以才没有推出跨平台的.net,只是推出了跨语言的.net,express|正则提要
文本处置常常触及的依据一个pattern的婚配。只管java的character和assorted的String类供应了low-level的pattern-matching撑持,这类撑持一样平常带来了庞大的代码。为了匡助你誊写复杂的pattern-matching代码,java供应了regularexpression。在先容给你术语和java.util.regex包以后,JeffFriesenexplores了很多谁人包的Pattern类撑持的正则表达式布局。然后他examines了Pattern的办法和附加的java.util.regex类。作为停止,他供应了一个正则表达式的理论使用。
为观察术语列表,提醒与告诫,新的homework,上个月homework的回覆,这篇文章的相干质料,请会见studyguide.(6,000words;February7,2003)
ByJeffFriesen,TranslatedByhumx
文本处置常常的请求根据特定pattern婚配的代码。它能让文本检索,emailheader考证,从一般文本的自界说文本的创立(比方,用"DearMr.Smith"替换"DearCustomer"),等等成为大概。Java经由过程character和assortedstring类撑持patternmatching。因为low-level的撑持一样平常带来了庞大的pattern-matching代码,java同时供应了regularexpression来简代码。
Regularexpressions常常让老手利诱。但是,这篇文章遣散了年夜部分搅浑。在先容了regularexpression术语,java.util.regex包中的类,和一个regularexpressionconstructs的示例程序以后,我explore了很多Pattern类撑持的regularexpressionconstructs。我也examine了构成Pattern和java.util.regex包中别的类的办法。一个practical的正则表达式的使用程序停止了我的会商。
Note
Regularexpressions的冗长汗青入手下手于盘算机迷信实际范畴主动把持道理和formal言语实际。它的汗青持续到Unix和别的的操纵体系,在那边正则表达式被常常用作在Unix和Unix-like的工具中:像awk(一个由其创作者,Aho,Weinberger,andKernighan,定名,可以举行文天职析处置的编程言语),emacs(一个开辟工具),和grep(一个在一个或多个文件中婚配正则表达式,为了全局地正则表达式打印的工具。
甚么是正则表达式?
Aregularexpression,也被knownasregexorregexp,是一个形貌了一个字符串汇合的pattern(template)。这个pattern决意了甚么样的字符串属于这个汇合,它由文本字符和元字符(metacharacters,由有特别的而不是字符寄义的字符)构成。为了辨认婚配的检索文本的历程―字符串满意一个正则表达式―称作形式婚配(patternmatching)。
Javasjava.util.regex包经由过程Pattern,Matcher类和PatternSyntaxException非常撑持patternmatching:
Pattern对象,被knownaspatterns,是编译的正则表达式。
Matcher对象,大概matchers,在,完成了java.lang.CharSequence接口并作为文本source的字符序列中定位注释matchers的引擎。
PatternSyntaxException对象形貌不法的regexpatterns。
Listing1先容这些类:
Listing1.RegexDemo.java
//RegexDemo.java
importjava.util.regex.*;
classRegexDemo{
publicstaticvoidmain(String[]args){
if(args.length!=2)
System.err.println("javaRegexDemoregextext");
return;
}
Patternp;
try{
p=Pattern.compile(args[0]);
}
catch(PatternSyntaxExceptione){
System.err.println("Regexsyntaxerror:"+e.getMessage());
System.err.println("Errordescription:"+e.getDescription());
System.err.println("Errorindex:"+e.getIndex());
System.err.println("Erroneouspattern:"+e.getPattern());
return;
}
Strings=cvtLineTerminators(args[1]);
Matcherm=p.matcher(s);
System.out.println("Regex="+args[0]);
System.out.println("Text="+s);
System.out.println();
while(m.find()){
System.out.println("Found"+m.group());
System.out.println("startingatindex"+m.start()+
"andendingatindex"+m.end());
System.out.println();
}
}
//Convert
andcharactersequencestotheirsinglecharacter
//equivalents
staticStringcvtLineTerminators(Strings){
StringBuffersb=newStringBuffer(80);
intoldindex=0,newindex;
while((newindex=s.indexOf("
",oldindex))!=-1){
sb.append(s.substring(oldindex,newindex));
oldindex=newindex+2;
sb.append(
);
}
sb.append(s.substring(oldindex));
s=sb.toString();
sb=newStringBuffer(80);
oldindex=0;
while((newindex=s.indexOf("
",oldindex))!=-1){
sb.append(s.substring(oldindex,newindex));
oldindex=newindex+2;
sb.append();
}
sb.append(s.substring(oldindex));
returnsb.toString();
}
}
RegexDemospublicstaticvoidmain(String[]args)办法validates两个命令行参数:一个指出正则表达式,别的一个指出文本。在创立一个pattern以后,这个办法转换一切的文本参数,new-lineandcarriage-returnline-terminator字符序列为它们的实践meanings。比方,一个new-line字符序列(由反斜杠后跟n暗示)转换成一个new-line字符(用数字暗示为10)。在输入了regex和被转换的命令行文本参数以后,main(String[]args)办法从pattern创立了一个matcher,它随后查找了一切的matches。关于每个match,它所呈现的字符和信息的地位被输入。
为了完成形式婚配,RegexDemo挪用了java.util.regex包中类的分歧的办法。不要使你本人如今就了解这些办法;我们将在后边的文章切磋它们。更主要的是,编译Listing1:你必要RegexDemo.class来探究Patternsregex布局。
探究Patternsregex机关
PatternsSDK文档供应了一部分正则表达式布局的文档。除非你是一个avid正则表达式利用者,一个最后的那段文档的浏览会让你利诱。甚么是quantifiers,greedy之间的分歧是甚么,reluctant,和possessivequantifiers?甚么是characterclasses,boundarymatchers,backreferences,和embeddedflagexpressions?为了回覆这些和别的的成绩,我们探究了很多Patter承认的regexconstructs或regexpattern品种。我们从最复杂的regexconstruct入手下手:literalstrings。
Caution
不要以为Pattern和Perl5的正则表达式布局是一样的。只管他们有良多不异点,他们也有很多,它们撑持的metacharacters布局的分歧点。(更多信息,观察在你的平台上的你的SDKPattern类的文档。)
Literalstrings
当你在字处置软件的检索对话框输出一个你指定一个literalstring的时分,你就指定了一个regexexpressionconstruct。实行以下的RegexDemo命令行来观察一下这个regexconstruct的举措:
javaRegexDemoappleapplet
上边的这个命令行断定了apple作为一个包括了字符a,p,p,l,ande(顺次)的字符regexconstruct。这个命令行同时也断定了applet作为pattern-matching的文本。实行命令行今后,看到以下输入:
Regex=apple
Text=applet
Foundapple
startingatindex0andendingatindex5
输入的regex和text命令行,预示着在applet中一个applet的乐成的婚配,并暗示了婚配的入手下手和停止的索引:分离为0和5。入手下手索引指出了一个patternmatch呈现的第一个文本的入手下手地位,停止索引指了然这个match后的第一个text的地位。换句话说,婚配的text的局限包括在入手下手索引和往失落停止索引之间(不包括停止索引)。
Metacharacters
只管stringregexconstructs是有效的,更壮大的regexcontsruct团结了文本字符和元字符。比方,在a.b,这个句点metacharacter(.)代表在a个b之间呈现的任何字符。为了观察元字符的举措,实行以下命令行:
javaRegexDemo.ox"Thequickbrownfoxjumpsoverthelazyox."
以上命令指出.ox作为regex,和Thequickbrownfoxjumpsoverthelazyox.作为文根源text。RegexDemo检索text来婚配以恣意字符入手下手以ox停止的match,并发生以下输入:
Regex=.ox
Text=Thequickbrownfoxjumpsoverthelazyox.
Foundfox
startingatindex16andendingatindex19
Foundox
startingatindex39andendingatindex42
这个输入展现了两个matches:fox和ox。.metacharacter在第一个match中婚配f,在第二个match中婚配空格。
假设我们用前述的metacharacter交换.ox会怎样呢?也就是,我们指定javaRegexDemo."Thequickbrownfoxjumpsoverthelazyox."会有甚么样的输入,由于periodmetacharacter婚配任何字符,RegexDemo在命令行输入每个婚配字符,包含开头的period字符。
Tip
为了指定.大概任何的元字符作为在一个regexconstruct作为literalcharacter,援用―转换meta形态到literalstatus―用以下两种办法之一:
在元字符之前安排反斜杠。
将元字符放在Q和E之间(比方:Q.E)。
在每种情况下,不要健忘在stringliteral(比方:Stringregex=.;
)中呈现时(像.orQ.E)的双倍的反斜杠。不要在当它在命令行参数中呈现的时分用双倍的反斜杠。
Characterclasses
偶然我们限制发生的matches到一个特定的字符集和。比方,我们能够检索元音a,e,i,o,andu,任何一个元音字符的呈现都觉得着一个match。Acharacter类,经由过程在方括号之间的一个字符集和指定的regexconstruct,帮我们完成这个义务。Pattern撑持以下的characterclasses:
复杂字符:撑持被顺次安排的字符串并仅婚配这些字符。比方:[abc]婚配字符a,b,andc。以下的命令行供应了别的一个示例:
javaRegexDemo[csw]cave
javaRegexDemo[csw]cave[csw]中c婚配在cave中的c。没有别的的婚配存在。
否认:以^metacharacter元字符入手下手且仅婚配没有在class中呈现的字符。比方:[^abc]婚配一切除a,b,和c之外的字符,以下的命令行供应了别的一个示例:
javaRegexDemo[^csw]cave
javaRegexDemo[^csw]cave婚配在cave中碰到的a,v,和e。没有别的的婚配存在。
局限:包括在元字符(-)左边的字符入手下手,元字符(-)右边字符停止的一切字符。仅婚配在局限内的字符。比方:[a-z]婚配一切的小写字母。以下的命令行供应了别的一个示例:
javaRegexDemo[a-c]clown
javaRegexDemo[a-c]clown婚配在clown中的c。没有别的的婚配存在。
Tip
经由过程将它们安排在一同来在一个rangecharacterclass内团结多个局限。比方:[a-zA-Z]婚配一切的年夜写和小写字母。
团结:由多个嵌套的characterclasses构成,婚配属于团结了局的一切字符。比方:[a-d[m-p]]婚配字符a到d和m到p。charactersathroughdandmthroughp。以下的命令行供应了别的一个示例:
javaRegexDemo[ab[c-e]]abcdef
javaRegexDemo[ab[c-e]]abcdef婚配它们在abcdef中的正本a,b,c,d,ande。没有别的的婚配存在。
交集:由一切嵌套的class的配合部分构成,且仅婚配字符的配合部分。比方:[a-z&&[d-f]]婚配字符d,e,和f。以下的命令行供应了别的一个示例:
javaRegexDemo[aeiouy&&[y]]party
javaRegexDemo[aeiouy&&[y]]party婚配在party中的y。没有别的的婚配存在。
差集:由除那些在否认嵌套characterclass中的字符外一切保存的字符构成。比方:[a-z&&[^m-p]]婚配字符a到l和q到z。以下的命令行供应了别的一个示例:
javaRegexDemo[a-f&&[^a-c]&&[^e]]abcdefg
javaRegexDemo[a-f&&[^a-c]&&[^e]]abcdefg婚配在abcdefg中的d和f。没有别的的婚配存在。
预界说的characterclasses
一些在regexes中呈现充足次数的characterclasses供应了shortcuts。Pattern用预界说的characterclass供应了如许的shortcuts,如Table1所示。利用预界说的characterclasses来简化你的regexes和最小化regex语法毛病。
Table1.预界说的characterclasses
Predefinedcharacterclass
Description
d
A数字。相称于[0-9]。
D
A非数字。相称于[^0-9]。
s
Awhitespacecharacter。相称于[
x0Bf]。
S
A非空格字符。相称于[^s]。
w
A一个字符。相称于[a-zA-Z_0-9]。
W
A非字符,相称于[^w]。
随后的命令行示例利用了w预界说characterclass来identify命令行中的一切wordcharacters。
javaRegexDemow"aZ.8_"
上边的命令行发生了以下的输入,它展现了句点和spacecharacters不被思索为wordcharacter:
Regex=w
Text=aZ.8_
Founda
startingatindex0andendingatindex1
FoundZ
startingatindex1andendingatindex2
Found8
startingatindex3andendingatindex4
Found_
startingatindex5andendingatindex6
Note
Pattern的SDK文档援用句点元字符作为婚配除lineterminator,一个大概两个标记一行停止的预界说的标记以外的任何字符,除非dotallmode(随后会商)无效。Pattern辨认以下lineterminators:
The回车符()
The回行符(
)
The回车符紧跟回行符(
)
The回行字符(u0085)
The行支解字符(u2028)
The段落支解字符(u2029)
捕捉组
Pattern撑持在pattern婚配的过程当中,一个regexconstruct挪用capturinggroup来保留为了今后recall的match的字符;此布局是由圆括号包抄的字符序列。在捕捉的group中的一切字符在婚配的过程当中被作为一个独自的单位。比方,(Java)capturinggroup分离了字符J,a,v,和a为一个独自单位。Capturinggroup根据在text中Java的呈现来婚配Javapattern。每个match用下一个婚配的Java字符替换了前一个match保留的Java字符。
Capturinggroups在别的capturinggroups内被嵌套。比方:在(Java(language)),(language)在(Java)内嵌套。每个嵌套或非嵌套的capturinggroup有它本人的数字,数字从1入手下手,Capturing数字从右边至右。在这个例子中,(Java(language))是capturinggroup1,(language)是capturinggroup2。在(a)(b),(a)是捕捉组1,(b)是捕捉组2。
每个capturinggroup随后经由过程abackreference来recall保留的match。指定跟从在一个反斜杠后的数字来唆使一个capturinggroup,backreference来recalls一个capturinggroup捕捉的文本字符。一个backreference的呈现招致了一个matcher利用thebackreference的capturinggroupnumber来recall捕捉组保留的match,然后利用婚配的字符举行进一步的婚配操纵。随后的示例树模了为了反省语法毛病举行的text搜刮的用法:
javaRegexDemo"(Java(language)2)""TheJavalanguagelanguage"
这个例子利用(Java(language)2)regex为了反省语法毛病,来检索字符串TheJavalanguagelanguage,那边Java间接地在两个一连呈现的language之前。Regex指定了两个capturinggroups:number1is(Java(language)2),它婚配Javalanguagelanguage,number2is(language),它婚配由language跟从的spacecharacer。2backreferencerecallsnumber2s保留的match,它同意matcher检索空格后跟从language的第二次呈现,which间接地跟从spacecharacterandlanguage的第一次呈现。随后的输入显现了RegexDemosmatcher找到了甚么:
Regex=(Java(language)2)
Text=TheJavalanguagelanguage
FoundJavalanguagelanguage
startingatindex4andendingatindex26
量词
Quantifiers也许是了解起来最使人利诱的regex布局。一部分搅浑来自于全力的了解18个量词逻辑(六个基础逻辑被构造为三个次要逻辑)。别的的一个搅浑来自于费尽的0长度婚配的了解。一旦你了解了这个观点和18categories,年夜部分(假设不是全体)搅浑将消散。
Note
扼要地,着一部分次要会商18个quantifiercategories和zero-length婚配的观点。为了更细致的会商和更多示例,请进修TheJavaTutoria的"Quantifiers"部分。
一个quantifier是一个隐式或显现的为一个pattern绑定一个数目值的正则表达式布局。这个数字值办理定了婚配一个pattern的次数。Pattern的六个基础的quantifiers婚配一个pattern一次大概基本不婚配,0次大概屡次,一次大概屡次,一个准确的数字次数,最少x次和最少x次但不凌驾y次。
六个基础的quantifiercategories在每个三个次要的种别:greedy,reluctant和possessive中复制。Greedyquantifiers实验找到最长的婚配。与之对比,reluctantquantifiers实验找到最短的婚配。Possessivequantifiers也实验找到最长的婚配。但是,他们和greedyquantifies在事情体例上分歧。只管greedy和possessivequantifiers迫使一个matcher在举行第一次婚配之前读取全部的text,greedyquantifiers经常招致为了找到一个match举行屡次实验,但是possessivequantifiers让一个matcher仅实验一个match一次。
随后的示例形貌了六种基础的quantifiers在greedycategory种别下,单个fundamentalquantifier在每个reluctant和possessivecategories种别下的举动。这些示例也形貌了0婚配的观点:
1.javaRegexDemoa?abaa:利用一个greedyquantifier来在abaa中婚配a一次大概基本不婚配。以下是输入了局:
Regex=a?
Text=abaa
Founda
startingatindex0andendingatindex1
Found
startingatindex1andendingatindex1
Founda
startingatindex2andendingatindex3
Founda
startingatindex3andendingatindex4
Found
startingatindex4andendingatindex4
这个输入展现了五次婚配。只管第1、三和四次婚配的呈现展现了三次婚配中地位其实不奇异,第1、第五次的婚配也许有点奇异。这个婚配仿佛指出a婚配b和文本的停止。但是,不是这类情形。a?其实不查找b和文本开头。相反,它查找a的呈现大概缺掉。当a?查找a失利的时分,它以零长度的婚配前往谁人现实(a缺掉),在零长度那边肇端和停止地位的索引不异。Zero-lengthmatches产生在空文本,最初一个文本字符以后,大概任何量个字符之间。
2.javaRegexDemoa*abaa:利用一个greedyquantifier在abaa中婚配a零次或屡次。以下是输入了局:
Regex=a*
Text=abaa
Founda
startingatindex0andendingatindex1
Found
startingatindex1andendingatindex1
Foundaa
startingatindex2andendingatindex4
Found
startingatindex4andendingatindex4
输入展现了四次婚配。像利用a?,a*发生了zero-length婚配。第三个婚配,a*婚配了aa,很风趣。不像a?,a*婚配一个大概多个一连的a。
3.javaRegexDemoa+abaa:利用一个greedyquantifier在abaa中婚配a一次或屡次。以下是输入了局:
Regex=a+
Text=abaa
Founda
startingatindex0andendingatindex1
Foundaa
startingatindex2andendingatindex4
输入展现了两个婚配。不像a?和a*,a+没有婚配a的却掉。因此,没有零长度婚配发生。像a*,a+婚配了一连的a。
4.javaRegexDemoa{2}aababbaaaab:利用greedyquantifier来婚配中的每个aababbaaaab中的aa序列。以下是输入了局:
Regex=a{2}
Text=aababbaaaab
Foundaa
startingatindex0andendingatindex2
Foundaa
startingatindex6andendingatindex8
Foundaa
startingatindex8andendingatindex10
5.javaRegexDemoa{2,}aababbaaaab:利用了greedyquantifier来婚配在ababbaaaab中两个或更多的婚配,以下是输入了局:
Regex=a{2,}
Text=aababbaaaab
Foundaa
startingatindex0andendingatindex2
Foundaaaa
startingatindex6andendingatindex10
6.javaRegexDemoa{1,3}aababbaaaab:利用greedyquantifier来婚配在aababbaaaab中呈现的a、aa大概aaa。以下是输入了局:
Regex=a{1,3}
Text=aababbaaaab
Foundaa
startingatindex0andendingatindex2
Founda
startingatindex3andendingatindex4
Foundaaa
startingatindex6andendingatindex9
Founda
startingatindex9andendingatindex10
7.javaRegexDemoa+?abaa:利用一个reluctantquantifier在abaa中一次或屡次婚配a。以下是输入了局:
Regex=a+?
Text=abaa
Founda
startingatindex0andendingatindex1
Founda
startingatindex2andendingatindex3
Founda
startingatindex3andendingatindex4
不像在第三个例中的greedy变量,reluctant示例发生了三个独自的婚配,由于reluctantquantifier全力的查找最短的婚配。
8.javaRegexDemo.*+end"Thisistheend":利用了possessivequantifier来婚配在thisistheend中的以end开头的恣意字符0次大概屡次。以下是输入了局:
Regex=.*+end
Text=Thisistheend
因为这个possessivequantifierconsume了全部文本,没有留下任何工具来婚配end,它没有发生婚配。比拟之下,在javaRegexDemo.*end"Thisistheend"的greedyquantifier,由于它每次backingoff一个字符直到最右真个end婚配,发生了一个婚配。(这个quantifier与greedy的分歧就在后者的婚配过程当中一旦婚配的字符,在随后的婚配中就不再利用。因而.*这部分正则表达式就婚配了全体的字符串,就没有字符能够与end婚配了。)
Boundarymatchers
我们偶然想在一行的入手下手、在单词的界限、文本的停止等等婚配pattern。利用boundarymatcher,一个指定了婚配界限的正则表达式布局,完成这个义务。Table2暗示了Pattern的界限婚配撑持。
Table2.Boundarymatchers
BoundaryMatcher
Description
^
一行的入手下手
$
一行的停止
单词的界限
B
非单词界限
A
文本的入手下手
G
前一个婚配的停止
Theendofthetext(butforthefinallineterminator,ifany)
z
文本停止
下边的命令行示例利用了^界限婚配元字符ensure由零个大概多个字符跟从的行入手下手。
javaRegexDemo^Thew*Therefore
^指出了前三个字符必需婚配pattern后的T、h和e字符。可跟从恣意数目的字符。以上的命令行发生以下输入:
Regex=^Thew*
Text=Therefore
FoundTherefore
startingatindex0andendingatindex9
把命令行改成javaRegexDemo^Thew*"Therefore"。产生了甚么事?由于在therefore前的一个空格,没有婚配被发明。
Embeddedflagexpressions
Matcher假定了断定的却省值,比方巨细写敏感的婚配。一个程序可使用anembeddedflagexpression来掩盖缺省值,也就是,利用一个正则表达式布局,圆括号元字符包抄一个问号元字符后跟小写字母。Pattern承认以下的embeddedflagexpressions:
(?i):enables巨细写不敏感的pattern婚配。比方:javaRegexDemo(?i)treeTreehouse来婚配tree和Tree。巨细写敏感是缺省值。
(?x):同意空格和正文用#元字符入手下手呈现在Pattern中。一个matcher疏忽全体它们。比方:javaRegexDemo".at(?x)#matchhat,cat,andsoon"matter婚配.at和mat。缺省地,空格和正文式不被同意的;一个matcher将它们思索为对match有奉献的字符。
(?s):使dotall体例无效。在这类形式中,句点除别的字符外还婚配text停止。比方:javaRegexDemo(?s).
,.婚配了
。Nondotall体例是缺省的:不婚配行开头。
(?m):使多行体例无效。在多行形式下^and$刚好分离的在一行的闭幕或末了以后大概之前。比方:javaRegexDemo(?m)^.akemakelake
take婚配.ake和make、lake与take。非多行形式是缺省的:^and$match仅在全部文本的入手下手和停止。
(?u):enablesUnicode-awarecasefolding.Thisflagworkswith(?i)toperformcase-insensitivematchinginamannerconsistentwiththeUnicodeStandard.Thedefault:case-insensitivematchingthatassumesonlycharactersintheUS-ASCIIcharactersetmatch。
(?d):enablesUnixlinesmode.Inthatmode,amatcherrecognizesonlythe
lineterminatorinthecontextofthe.,^,and$metacharacters.Non-Unixlinesmodeisthedefault:amatcherrecognizesallterminatorsinthecontextoftheaforementionedmetacharacters。
Embeddedflagexpressions相似于capturinggroups由于两个regexconstructs都用圆括号包抄字符。不像capturinggroup,embeddedflagexpression没有捕捉婚配的字符。因此,一个embeddedflagexpression是noncapturinggroup的惯例。也就是说,一个不捕捉text字符的regexconstruct;它指定了由元字符圆括号包抄的字符序列。在PatternsSDK文档中呈现了一些noncapturinggroups。
Tip
为了在正则表达式中指定多个embeddedflag表达式。大概吧它们并排的放在一同(e.g.,(?m)(?i))大概把它们的小写字母并排的放在一同(e.g.,(?mi))。
探究java.util.regex类的办法
java.util.regex包的三个类供应了为帮我誊写更强健的正则表达式代码和创立壮大的text处置工具很多的办法。我们从Pattern类入手下手探究这些办法。
Note
你也能够exploreCharSequence接口确当你创立一个新的字符序列类要完成的办法。仅完成CharSequence接口的类是java.nio.CharBuffer,String,和StringBuffer。
Pattern办法
除非代码将一个string编译为Pattern对象一个regex表达式式没有效处的。用以下编纂办法中的一个完成这个义务:
publicstaticPatterncompile(Stringregex):将regex内容编译为在一个新的Pattern对象内存储的树状布局的对象暗示。前往谁人对象援用。比方:Patternp=Pattern.compile("(?m)^.");创立了一个,存储了一个编译的暗示了婚配以句点入手下手的行的暗示。
publicstaticPatterncompile(Stringregex,intflags):完成前一个办法的不异义务。但是,它同时思索包括了flag常量(flags指定的)。Flag常量在Pattern中(exceptthecanonicalequivalenceflag,CANON_EQ)被作为二选一的embeddedflagexpressions被声明。比方:Patternp=Pattern.compile("^.",Pattern.MULTILINE);和上一个例子等价,Pattern.MULTILINE常量和the(?m)embeddedflag表达式完成不异的义务。(参考SDKsPattern文档进修别的的常量。)假设不是这些在Pattern中被界说的常量在flag中呈现,办法将抛出IllegalArgumentException非常。
假设必要,经由过程挪用以下办法能够失掉一个Pattern对象的flag和最后的被编译为对象的正则表达式:
publicintflags():前往当正则表达式编译时指定的Pattern的flag。比方:System.out.println(p.flags());输入p援用的的Pattern相干的flag。
publicStringpattern():前往最后的被编译进Pattern的正则表达式。比方:System.out.println(p.pattern());输入对应p援用Pattern的正则表达式。(Matcher类包括了相似的前往Matcher相干的Pattern对象的Patternpattern()办法。)
在创立一个Pattern对象后,你一样平常的经由过程挪用Pattern的私有办法matcher(CharSequencetext)取得一个Matcher对象。这个办法必要一个复杂的,完成了CharSequence接口的文本对象参数。取得的对象在pattern婚配的过程当中扫描输出的文本对象。比方:Patternp=Pattern.compile("[^aeiouy]");Matcherm=p.matcher("Thisisatest.");取得一个在text中婚配一切非元音字母的matcher。
当你想反省一个pattern是不是完整的婚配一个文本序列的时分创立Pattern和Matcher对象是使人懊恼的。侥幸的是,Pattern供应了一个便利的办法完成这个义务;publicstaticbooleanmatches(Stringregex,CharSequencetext)。当且仅当全部字符序列婚配regex的pattern的场所下静态办法前往布尔值true。比方:System.out.println(Pattern.matches("[a-z[s]]*","alllowercaselettersandwhitespaceonly"));前往布尔值true,指出仅空格字符和小写字符在alllowercaselettersandwhitespaceonly中呈现。
誊写代码将text分红它的构成部分(比方雇员纪录文件到一个字段的set)是很多开辟者发明有趣的义务。Pattern经由过程供应一对字符支解办法来加重那种tedium。
publicString[]split(CharSequencetext,intlimit):支解在以后的Pattern对象的pattern婚配四周的text。这个办法前往一个数组,它的每个条目指定了一个从下一个由pattern婚配(大概文本停止)分隔的字符序列;且一切条目以它们在text中呈现不异的按次存储。书组条目标数目依附于limit,它同时也把持了婚配产生次数。一个负数意味着,最多,limit-1个婚配被思索且数组的长度不年夜于限制的条目数。一个负值觉得着一切婚配的大概都被思索且数组能够恣意长。一个0值觉得着一切大概婚配的条目都被思索,数组能够有恣意的长度,且尾部的空字符串被抛弃。
publicString[]split(CharSequencetext):用0作为限定挪用前边办法,前往办法挪用的了局。
假设你想一个拆分雇员纪录,包括了姓名,岁数,街道和人为,为它的构成部分。以下的代码用split(CharSequencetext)办法完成了这个义务:
Patternp=Pattern.compile(",s");
String[]fields=p.split("JohnDoe,47,HillsboroRoad,32000");
for(inti=0;i<fields.length;i++)
System.out.println(fields[i]);
Thecodefragmentabovespecifiesaregexthatmatchesacommacharacterimmediatelyfollowedbyasingle-spacecharacterandproducesthefollowingoutput:
JohnDoe
47
HillsboroRoad
32000
Note
String兼并了三个便利的办法挪用它们等价的Pattern办法:publicbooleanmatches(Stringregex),publicString[]split(Stringregex),andpublicString[]split(Stringregex,intlimit)。
Matcher办法
Matcher对象撑持分歧范例的pattern婚配操纵,比方扫描text查找下一个match;实验依据一个pattern来婚配全部文本;依据一个pattern实验婚配部分text。用以下的办法完成这些义务:
publicbooleanfind():扫描text查找下一个match。此办法,大概在text的入手下手扫描,假设上一次的办法挪用前往true且这个matcher没有被reset,在前一个match后的第一个字符入手下手扫描。假设一个match被找到的话前往布尔值true。Listing1展现了一个例子。
publicbooleanfind(intstart):从头布置matcher扫描下一个match。扫描从start指定的index入手下手。假设一个match被找到的话前往布尔值true。比方:m.find(1);从index1入手下手扫描。(索引0被疏忽。)假设start包括了一个正数大概一个超越了matcfher的text长度的值,这个办法抛出IndexOutOfBoundsException非常。
publicbooleanmatches():实验依据pattern婚配全部text。在这个text婚配的情况下前往true。比方:Patternp=Pattern.compile("w*");Matcherm=p.matcher("abc!");System.out.println(m.matches());输入false由于全部abc!text包括了非字母wordcharacters。
publicbooleanlookingAt():实验依据pattern婚配text。假设一个match被找到的话前往布尔值true。不像matches(),全部text不必要被婚配。比方:Patternp=Pattern.compile("w*");Matcherm=p.matcher("abc!");System.out.println(p.lookingAt());输入true由于textabc!的入手下手部分仅包括word字符。
不像Pattern对象,Matcher包括了形态信息。偶然,你在一个pattern婚配后想reset一个matcher扫除那些信息。下边的办法reset了一个matcher:
publicMatcherreset():重置了一个matcher的形态,包含matcher的appendposition(被扫除为0)。下一个pattern的婚配操纵从matcher新文本的肇端入手下手。前往以后的matcher对象援用。比方:m.reset();经由过程援用m重置了matcher。
publicMatcherreset(CharSequencetext):从头设置一个matcher的形态且设置了matcher的文本内同。下一个pattern的婚配操纵在matcher新的文本的肇端地位入手下手。前往以后的matcher对象援用。比方:m.reset("newtext");重置m援用的对象并制订新的text作为matcher的新text。
一个matcher的appendposition决意了matcher的text的追加到一个StringBuffer对象中的入手下手地位。以下的办法利用了appendposition:
publicMatcherappendReplacement(StringBuffersb,Stringreplacement):读取matcher的text并将它们追加到sb援用的StringBuffer对象。这个办法在前一个patternmatch的最初一个字符以后中断读取。此method然后增加replacement援用的中的characters到StringBuffer对象。(交换字符串能够包括上一个婚配捕捉的文本的援用,经由过程dollar-signcharacters($)和capturinggroup数)终极,这个办法设置了matcher的appendposition为最初一个婚配字符的地位加上1。一个以后的matcher对象的援用前往。假设这个matcher对象还没有实行match大概前次的match实验失利此办法将抛出一个IllegalStateException非常。假设replacement指定了一个pattern中不存在的capturinggroup一个IndexOutOfBoundsException非常将被抛出。
publicStringBufferappendTail(StringBuffersb):追加一切的text到StringBuffer对象并前往对象援用。在最初一次挪用appendReplacement(StringBuffersb,Stringreplacement)办法以后,挪用appendTail(StringBuffersb)copy残剩的text到StringBuffer对象。
随后的例子挪用appendReplacement(StringBuffersb,Stringreplacement)和appendTail(StringBuffersb)办法来交换一切在onecat,twocats,orthreecatsonafence中呈现的cat为caterpillar。一个capturinggroup和在replacement中的capturinggroup的援用同意在每个cat婚配后拔出erpillar:
Patternp=Pattern.compile("(cat)");
Matcherm=p.matcher("onecat,twocats,orthreecatsonafence");
StringBuffersb=newStringBuffer();
while(m.find())
m.appendReplacement(sb,"$1erpillar");
m.appendTail(sb);
System.out.println(sb);
此示例发生以下输入:
onecaterpillar,twocaterpillars,orthreecaterpillarsonafence
别的的两个交换办法利用交换的文本交换第一个match和一切的match成为大概:
publicStringreplaceFirst(Stringreplacement):重置matcher,创立一个新的String对象,拷贝一切婚配的文本字符(直到第一个match)到String,追加交换字符到String,拷贝残剩的字符到Strring,并前往对象援用。(交换字符串能够包括上一个婚配捕捉的文本的援用,经由过程dollar-signcharacters($)和capturinggroup数。)
publicStringreplaceAll(Stringreplacement):操纵和上一个办法相似。但是,replaceAll(Stringreplacement)用交换字符交换一切婚配。
正则表达式s+探测在文本中呈现的一次或屡次呈现的空格。随后的例子利用了这个regex并挪用了replaceAll(Stringreplacement)办法来从text删除duplicatewhitespace:
Patternp=Pattern.compile("s+");
Matcherm=p.matcher("Removethe duplicatewhitespace.");
System.out.println(m.replaceAll(""));
此示例发生以下输入:
Removetheduplicatewhitespace.
Listing1包括了System.out.println("Found"+m.group());.注重办法挪用group()。此办法是capturinggroup-oriented的Matcher办法:
publicintgroupCount():前往在matcher的pattern中capturinggroups的个数。这个计数没有包括特定的capturinggroup数字0,它捕捉前一个match(不论一个pattern包括capturinggroups与否。)
publicStringgroup():经由过程capturinggroup数字0纪录前往上一个match的字符。此办法能够依据一个空的字符串前往一个空字符串。假设match还没有被实验大概前次的match操纵失利将抛出IllegalStateException非常。
publicStringgroup(intgroup):像上一个办法,除经由过程group指定的capturinggroupnumber前往之前的match字符外。假设没有groupnumber指定的capturinggroup在pattern中存在,此办法抛出一个IndexOutOfBoundsException非常。
以下代码树模了thecapturinggroup办法:
Patternp=Pattern.compile("(.(.(.)))");
Matcherm=p.matcher("abc");
m.find();
System.out.println(m.groupCount());
for(inti=0;i<=m.groupCount();i++)
System.out.println(i+":"+m.group(i));
Theexampleproducesthefollowingoutput:
3
0:abc
1:abc
2:bc
3:c
Capturinggroup数字0保留了previousmatch且与hasnothingtodowithwhether一个capturinggroup在一个pattern中呈现与否没有任何干系。也就是is(.(.(.)))。别的的三个capturinggroups捕捉了previousmatch属于这个capturinggroups的字符。比方,number2,(.(.)),捕捉bc;andnumber3,(.),捕捉c.
在我们分开会商Matcher的办法之前,我们将examine四个match地位办法:
publicintstart():前往previousmatch的入手下手地位。假设match还没有被实行大概前次的match失利,此办法抛出一个IllegalStateException非常。
publicintstart(intgroup):相似上一个办法,除前往group指定的capturinggroup的相干的previousmatch的入手下手索引外,假设在pattern中没有指定的capturinggroupnumber存在,start(intgroup)抛出IndexOutOfBoundsException非常。
publicintend():前往前次match中婚配的字符的索引地位加上1。假设match还没有被实验大概前次的match操纵失利将抛出IllegalStateException非常。
publicintend(intgroup):相似上一个办法,除前往group指定的capturinggroup的相干的previousmatch的end索引外。假设在pattern中没有指定的capturinggroupnumber存在,end(intgroup)抛出IndexOutOfBoundsException非常。
下边的示例树模了两个matchposition办法,为capturinggroupnumber2呈报肇端/停止match地位:
Patternp=Pattern.compile("(.(.(.)))");
Matcherm=p.matcher("abcabcabc");
while(m.find())
{
System.out.println("Found"+m.group(2));
System.out.println("startingatindex"+m.start(2)+
"andendingatindex"+m.end(2));
System.out.println();
}
Theexampleproducesthefollowingoutput:
Foundbc
startingatindex1andendingatindex3
Foundbc
startingatindex4andendingatindex6
Foundbc
startingatindex7andendingatindex9
输入show我们仅仅对与capturinggroupnumber2相干的matcher感乐趣,也就是这些婚配的肇端停止地位。
Note
String引进了两个便利的和挪用Matcher等价的办法:publicStringreplaceFirst(Stringregex,Stringreplacement)和publicStringreplaceAll(Stringregex,Stringreplacement)。
PatternSyntaxExceptionmethods
Pattern的办法当它们发明不法的正则表达式语法毛病的时分抛出PatternSyntaxException非常。一个非常处置器能够挪用PatternSyntaxException的办法来取得抛出的关于语法毛病的PatternSyntaxException对象的信息。
publicStringgetDescription():前往语法毛病形貌。
publicintgetIndex():前往语法毛病产生地位的近似索引或-1,假设index是未知的。
publicStringgetMessage():创建一个多行的,包括了别的三个办法前往的信息的综合,以可视的体例指出在pattern中毛病的地位字符串。
publicStringgetPattern():前往不准确的正则表达式。
由于PatternSyntaxException从java.lang.RuntimeException承继而来,代码不必要指定毛病handler。Thisprovesappropriatewhenregexesareknowntohavecorrectpatterns。但当有潜伏的pattern语法毛病存在的时分,一个非常handler是必须的。因此,RegexDemo的源代码(参看Listing1)包括了try{...}catch(ParseSyntaxExceptione){...},它们挪用了PatternSyntaxException四个非常办法中的每个来取得不法pattern的信息。
甚么构成了不法的pattern?在embeddedflagexpression中没有指定停止的元字符停止标记就是一个例。假设你实行javaRegexDemo(?itreeTreehouse。此命令的不法正则表达式(?treepattern招致p=Pattern.compile(args[0]);抛出PatternSyntaxException非常。你将看到以下输入:
Regexsyntaxerror:Unknowninlinemodifiernearindex3
(?itree
^
Errordescription:Unknowninlinemodifier
Errorindex:3
Erroneouspattern:(?itree
Note
publicPatternSyntaxException(Stringdesc,Stringregex,intindex)机关函数让你创立你本人的PatternSyntaxException对象,Thatconstructorcomesinhandyshouldyouevercreateyourownpreprocessingcompilationmethodthatrecognizesyourownpatternsyntax,translatesthatsyntaxtosyntaxrecognizedbyPatternscompilationmethods,andcallsoneofthosecompilationmethods.Ifyourmethodscallerviolatesyourcustompatternsyntax,youcanthrowanappropriatePatternSyntaxExceptionobjectfromthatmethod。
一个正则表达式使用理论
Regexesletyoucreatepowerfultext-processingapplications.OneapplicationyoumightfindhelpfulextractscommentsfromaJava,C,orC++sourcefile,andrecordsthosecommentsinanotherfile.Listing2presentsthatapplicationssourcecode:
Listing2.ExtCmnt.java
//ExtCmnt.java
importjava.io.*;
importjava.util.regex.*;
classExtCmnt
{
publicstaticvoidmain(String[]args)
{
if(args.length!=2)
{
System.err.println("usage:javaExtCmntinfileoutfile");
return;
}
Patternp;
try
{
//Thefollowingpatternletsthisextractmultilinecommentsthat
//appearonasingleline(e.g.,/*sameline*/)andsingle-line
//comments(e.g.,//someline).Furthermore,thecommentmay
//appearanywhereontheline.
p=Pattern.compile(".*/*.**/|.*//.*$");
}
catch(PatternSyntaxExceptione)
{
System.err.println("Regexsyntaxerror:"+e.getMessage());
System.err.println("Errordescription:"+e.getDescription());
System.err.println("Errorindex:"+e.getIndex());
System.err.println("Erroneouspattern:"+e.getPattern());
return;
}
BufferedReaderbr=null;
BufferedWriterbw=null;
try
{
FileReaderfr=newFileReader(args[0]);
br=newBufferedReader(fr);
FileWriterfw=newFileWriter(args[1]);
bw=newBufferedWriter(fw);
Matcherm=p.matcher("");
Stringline;
while((line=br.readLine())!=null)
{
m.reset(line);
if(m.matches())/*entirelinemustmatch*/
{
bw.write(line);
bw.newLine();
}
}
}
catch(IOExceptione)
{
System.err.println(e.getMessage());
return;
}
finally//Closefile.
{
try
{
if(br!=null)
br.close();
if(bw!=null)
bw.close();
}
catch(IOExceptione)
{
}
}
}
}
在创立Pattern和Matcher对象以后,ExtCmnt逐行的读取一个文本文件的内容。关于每行,matcher实验婚配pattern的行,判别是一个单行的正文大概多行的正文在一行中呈现。假设一行婚配pattern,ExtCmnt将此行写进别的一个文本文件中。比方,javaExtCmntExtCmnt.javaout读取ExtCmnt.java文件的每行,依据pattern来实验着一行,将婚配的行输入到名叫out的文件。(不要忧虑了解文件的读写逻辑。我将在未来的文章中explore这些代码。)在ExtCmnt实行完成,out文件包括了以下行:
//ExtCmnt.java
//Thefollowingpatternletsthisextractmultilinecommentsthat
//appearonasingleline(e.g.,/*sameline*/)andsingle-line
//comments(e.g.,//someline).Furthermore,thecommentmay
//appearanywhereontheline.
p=Pattern.compile(".*/*.**/|.*//.*$");
if(m.matches())/*entirelinemustmatch*/
finally//Closefile.
这个输入显现ExtCmnt其实不完善:p=Pattern.compile(".*/*.**/|.*//.*$");没有刻画一个正文。呈现在out中的行由于ExtCmnt的matcher婚配了//字符。
关于pattern".*/*.**/|.*//.*$"由一些风趣的事,竖线元字符metacharacter(|)。按照SDKdocumentation,圆括号元字符在capturinggroup和竖线元字符是逻辑操纵标记。verticalbar形貌了一个matcher,它利用操纵符左边的正则表达式布局来在matcher的文本中定为一个match。假设没有match存在,matcher利用操纵标记右边的正则表达式举行再次的婚配实验。
复习
只管正则表达式简化了在text处置程序中pattern婚配的代码,除非你了解它们,不然你不克不及无效的在你的程序中利用正则表达式。这篇文章经由过程先容给你regexterminology,thejava.util.regex包和树模regexconstructs的程序来让你对正则表达式有一个基础的了解。既然你对regexes有了一个基础的了解,创建在经由过程浏览additionalarticles(seeResources)和进修java.util.regexsSDK文档,那边你能够进修更多的regexconstructs,比方POSIX(PortableOperatingSystemInterfaceforUnix)字符类。
我勉励你用这篇文章中大概别的之前文章中材料中成绩emailme。(请坚持成绩和这个栏目会商的文章相干性。)你的成绩和我的回覆将呈现在相干的进修guides中。)
AfterwritingJava101articlesfor28consecutivemonths,Imtakingatwo-monthbreak.IllreturninMayandintroduceaseriesondatastructuresandalgorithms.
Abouttheauthor
JeffFriesenhasbeeninvolvedwithcomputersforthepast23years.Heholdsadegreeincomputerscienceandhasworkedwithmanycomputerlanguages.JeffhasalsotaughtintroductoryJavaprogrammingatthecollegelevel.InadditiontowritingforJavaWorld,hehaswrittenhisownJavabookforbeginners―Java2byExample,SecondEdition(QuePublishing,2001;ISBN:0789725932)―andhelpedwriteUsingJava2Platform,SpecialEdition(QuePublishing,2001;ISBN:0789724685).JeffgoesbythenicknameJavaJeff(orJavaJeff).Toseewhathesworkingon,checkouthisWebsiteathttp://www.javajeff.com.
Resources
Downloadthisarticlessourcecodeandresourcefiles:
http://www.javaworld.com/javaworld/jw-02-2003/java101/jw-0207-java101.zip
Foraglossaryspecifictothisarticle,homework,andmore,seetheJava101studyguidethataccompaniesthisarticle:
http://www.javaworld.com/javaworld/jw-02-2003/jw-0207-java101guide.html
"MagicwithMerlin:ParseSequencesofCharacterswiththeNewregexLibrary,"JohnZukowski(IBMdeveloperWorks,August2002)exploresjava.util.regexssupportforpatternmatchingandpresentsacompleteexamplethatfindsthelongestwordinatextfile:
http://www-106.ibm.com/developerworks/java/library/j-mer0827/
"MatchmakingwithRegularExpressions,"BenedictChng(JavaWorld,July2001)exploresregexesinthecontextofApachesJakartaOROlibrary:
http://www.javaworld.com/javaworld/jw-07-2001/jw-0713-regex.html
"RegularExpressionsandtheJavaProgrammingLanguage,"DanaNourieandMikeMcCloskey(SunMicrosystems,August2002)presentsabriefoverviewofjava.util.regex,includingfiveillustrativeregex-basedapplications:
http://developer.java.sun.com/developer/technicalArticles/releases/1.4regex/
In"TheJavaPlatform"(onJava.com),anexcerptfromChapter4ofOReillysJavainaNutshell,4thEdition,DavidFlanaganpresentsshortexamplesofCharSequenceandjava.util.regexmethods:
http://www.onjava.com/pub/a/onjava/excerpt/javanut4_ch04
TheJavaTutorials"RegularExpressions"lessonteachesthebasicsofSunsjava.util.regexpackage:
http://java.sun.com/docs/books/tutorial/extra/regex/index.html
Wikipediadefinessomeregexterminology,presentsabriefhistoryofregexes,andexploresvariousregexsyntaxes:
http://www.wikipedia.org/wiki/Regular_expression
ReadJeffspreviousJava101column:"ToolsoftheTrade,Part3"(JavaWorld,January2003):
http://www.javaworld.com/javaworld/jw-01-2003/jw-0103-java101.html?
CheckoutpastJava101articles:
http://www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html
BrowsetheCoreJavasectionofJavaWorldsTopicalIndex:
http://www.javaworld.com/channel_content/jw-core-index.shtml
NeedsomeJavahelp?VisitourJavaBeginnerdiscussion:
http://forums.devworld.com/webx?50@@.ee6b804
JavaexpertsansweryourtoughestJavaquestionsinJavaWorldsJavaQ&Acolumn:
http://www.javaworld.com/javaworld/javaqa/javaqa-index.html
ForTipsNTricks,see:
http://www.javaworld.com/javaworld/javatips/jw-javatips.index.html
SignupforJavaWorldsfreeweeklyCoreJavaemailnewsletter:
http://www.javaworld.com/subscribe
YoullfindawealthofIT-relatedarticlesfromoursisterpublicationsatIDG.net
你通过从书的数量和开发周期及运行速度来证明:net和ruby要比java简单。 |
|