正则表达式语法:
语法 解释
字符:
c|字符c
\unnnn, \xnn,\0n,\0nn,\0nnn|具有给定十六进制或十进制的码元
\t,\n,\r,\f,\a,\e|控制符:制表符、换行符、回车符、换页符、警告符、逃逸符
\cc|与字符c相关的控制符
字符类:
[C1C2...]|任何由C1,C2...表示的字符,其中Ci可以是多个字符、字符范围是C1-C2或字符类
[^......] |字符类的补集
[...&&..] |两个字符集的交集
预定义字符类:
除了行终止符之外所有的字符(在DOTALL标志被设置时,则表示所有字符)
\d|一个数字[0-9]
\D|一个非数字[0-9]
\s|一个空白字符[\t\n\t\f\x0B]
\S|一个非空白字符
\w|一个词语字符[a-zA-Z0-9]
\W|一个非词语字符
\p{name}|一个命名字符类
\P{name}|一个命名字符类的补集
边界匹配符:^$ |输入的开头和结尾
\b|一个词语边界
\B|一个非词语字符
\A|输入的开头
\z|输入的结尾
\Z|除了终止符之外的输入结尾
\G|前一个匹配的结尾
量词:
X? |可选的X
X* |X重复0或多次
X+ |X重复1或多次
X{n}X{n,}X{n,m}|X重复n次,至少n次,在n到m次之间
量词后缀:? |将默认(贪婪)匹配转变为勉强匹配+ |将默认(贪婪)匹配转变为占有匹配
集合操作:
XY|任何X中的字符串,后面跟随任何Y中的字符串
X|Y |任何X或Y的字符串
群组:
(X)|捕获将X作为群组匹配的字符串
\n|第n个群组的匹配
转义:
\c|字符c(必须是不在字母表中的字符)
\Q.....\E|逐字的引用...
(?...) |特殊结构
View Code
一、正则表达式基础知识
我们从简单的开始,假设你要搜索一个包含字符cat的字符串,搜索用的正则表达式是cat。如果搜索对大小写不敏感,单词catalog、Catherine、sophisticated都可以匹配。也就是说:
正则表达式:cat
匹配:cat,catalog,Catherine,sophisticated
1.1 句点符号
比如说,想要找出三个字母的单词,而且这些单词必须以t开头,以n结束。另外,假设有一个字典,你可以用正则表达式搜索全部内容。则可以用t.n来进行匹配。
1.2 方括号符号
比如说,可以用[]进行进一步匹配,避免过于广泛。
正则表达式:t[aeio]n
匹配:tan,Ten,tin,ton1.3 或符号
如果除了上面匹配的所有单词之外,你还想要匹配“toon”,那么,你可以使用“|”操作符。“|”操作符的基本意义就是“或”运算。要匹配
“toon”,使用“t(a|e|i|o|oo)n”正则表达式。这里不能使用方扩号,因为方括号只允许匹配单个字符;这里必须使用圆括号“()”。圆括
号还可以用来分组。
正则表达式:t(a|e|i|o|oo)n
匹配:tan,ten,tin,ton,toon
1.3表示匹配次数的符号
见正则表达式语法的量词。
如999-99-9999 [0-9]{3}\-[0-9]{2}\-[0-9]{4}
999999999和999-99-9999 [0-9]{3}\-?[0-9]{2}\-?[0-9]{4}
8836KV [0-9]{4}[a-z]{2}
1.4 否符号
^称为否符号,表示不想匹配的字符。如^a:第一个字符不能是a。[^a][a-z]+即:匹配开头不是a的全部单词。
1.5 圆括号和空白字符
如从June 26,1951的生日中提出月份部分,则可以用:
[a-z]+ \s+[0-9]{1-2},\s*[0-9]{4}:匹配该日期的正则表达式。
([a-z]+) \s+[0-9]{1-2},\s*[0-9]{4}:匹配该日期的月份正则表达式。
二、具体的例子分析
2.1电话号码匹配
设计一个简单的表达式来匹配任何电话号码数字可能是比较复杂的事情,原因在于电话号码格式有很多种情况。所有必须选择一个比较有效的模式。比如:(212) 555-1212, 212-555-1212和212 555 1212,某些人会认为它们都是等价的。
首先让我们构成一个正则表达式。为简单起见,先构成一个正则表达式来识别下面格式的电话号码数字:(nnn)nnn-nnnn。
第一步,创建一个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}
下面的一段代码实现的功能是,从一个文本文件逐行读入,并逐行搜索电话号码数字,一旦找到所匹配的,然后输出在控制台。
1 packageperl;2 import java.io.*;3 import java.util.regex.*;4 public classtest_number {5 public static void main(String[] args) throwsIOException{6 BufferedReader in;7 Pattern pattern=Pattern.compile("\\(\\d{3}\\)\\s\\d{3}-\\d{4}");8 in=new BufferedReader(new FileReader("C:/Users/liuzhongfeng/Desktop/文件/java/phone.txt"));9 String s;10 while((s=in.readLine())!=null){11 Matcher matcher=pattern.matcher(s);12 if(matcher.find()){13 System.out.println(matcher.group());14 }15 }16 in.close();17 }18 }
View Code
结果为:
(121) 525-1111(000) 545-5555(000) 545-5555原文为:
(121) 525-1111(000) 545-5555(000)-545-5555(000) 545-55555(000)-545-5555
对于程序中的find()函数,用来匹配搜索与正则表达式相匹配id任何目标字符串,group()方法,用来返回包含了所匹配文本的字符串,应注意的是,上面的代码,仅用在每行只能含有一个匹配的电话号码数字字符串时。可以肯定的说,java的正则表达式包能用在一行含有多个匹配目标时的搜索。这相当漂亮吧! 但是很遗憾的是,这仅是个电话号码匹配器。
很明显,还有两点可以改进。如果在电话号码的开头,即区位号和本地号码之间可能会有空格。我们也可匹配这些情况,则通过在正则表达式中加入/s?来实现,其中?元字符表示在模式可能有0或1个空格符。
第二点是,在本地号码位的前三位和后四位数字间有可能是空格符,而不是连字号,更有胜者,或根本就没有分隔符,就是7位数字连在一起。对这几种情况,我们 可以用(-|)?来解决。这个结构的正则表达式就是转换器,它能匹配上面所说的几种情况。在()能含有管道符|时,它能匹配是否含有空格符或连字符,而尾 部的?元字符表示是否根本没有分隔符的情况。最后,区位号也可能没有包含在圆括号内,对此可以简单地在圆括号后附上?元字符,但这不是一个很好的解决方法。因为它也包含了不配对的圆括号,比如" (555" 或 "555)"。相反,我们可以通过另一种转换器来强迫让电话号码是否带有有圆括号:(\(\d{3}\)|\d{3})。如果我们把上面代码中的正则表达 式用这些改进后的来替换的话,上面的代码就成了一个非常有用的电话号码数字匹配器:Pattern pattern =Pattern.compile("(\\(\\d{3}\\)|\\d{3})\\s?\\d{3}(-|)?\\d{4}");
可以确定的是,你可以自己试着进一步改进上面的代码。
2.2检查文本中是否有重复的单词
1.第二个例子:它是从Friedl的中改编过来的,其功能是检查文本中是否有重复的单词,这在印刷排版中会经常遇到,同样也是个语法检查器的问题。
匹配单词好几种正则表达式,最可能直接的是\b\w+\b,优点是只需少量的regex元字符。其中/w元字符用来匹配从字母a到u的任何字符。+元字符表示匹配匹配一次或多次字符,/b元字符是用来说明匹配单词的边界,它可以是空格或任何一种不同的标点符号(包括逗号,句号等)。
圆括号在正则表达式中有几种不同的用法,一个就是能提供组合类型,组合类型用来保存所匹配的结果或部分匹配的结果(以便后面能用到),即使遇到有相同的模 式。在同样的正则表达中,可能(也通常期望)不止有一个组合类型。在第n个组合类型中匹配结果可以通过向后扫描来获取到。向后扫描使得搜索重复的单词非常 简单:\b(\w+)\s+\1\b。向后扫描\1,指的是任何被\w+所匹配的单词。我们的正则表达式因此能匹配这样的,它有一个或多个空格符,后面还跟有一个与此相同的单词。
最后进一步的修改是让我们的匹配器对大小写敏感。比如,下面的情况:"The the theme of this article is the Java's regex package.",这一点在regex中能非常简单地实现,即通过使用在Pattern类中预定义的静态标志CASE_INSENSITIVE。
pattern pattern=Pattern.compile("\\b(\\w+)\\s+\\1\\b");
Pattern.CASE_INSENSITIVE();
2、CharSequence
JDK 1.4定义了一个新的接口,它提供了String和StringBuffer这两个类的字符序列的抽象。
interface CharSequence{
charAt(int i);
length();
subSequence(int start,int end);
toString();
}
3、Pattern和Matcher
先给一个例子。下面这段程序可以测试正则表达式是否匹配字符串。第一个参数是要匹配的字符串,后面是正则表达式。正则表达式可以有多个。在Unix/Linux环境下,命令行下的正则表达式还必须用引号。
Java的正则表达式是由java.util.regex的Pattern和Matcher类实现的。Pattern对象表示经编译的正则表达式。静态的compile( )方法负责将表示正则表达式的字符串编译成Pattern对象。正如上述例程所示的,只要给Pattern的matcher( )方法送一个字符串就能获取一个Matcher对象。只要给Pattern matcher()方法传一个字符串就能够获得Matcher的方法来查询匹配的结果了。
boolean matches()
boolean lookingAt()
boolean find()
boolean find(int start)
matches()的前提是Pattern匹配整个字符串,而lookingAt()的意思是Pattern匹配字符串的开头。对于find()函数,Matcher.find()的功能是发现CharSequence里的,与pattern相匹配的多个字符序列。例如:
1 packageperl;2
3 import java.util.regex.*;4 //import com.bruceeckel.simpletest.*
5 import javax.management.monitor.*;6 import java.util.*;7 import java.io.*;8 public classFindDemo {9 public static void main(String[] args) throwsIOException{10 BufferedReader in;String str;11 in=new BufferedReader(new FileReader("C:/Users/liuzhongfeng/Desktop/文件/java/find.txt"));12 Matcher m=Pattern.compile("\\w+").matcher("Evening is full of the linnet's wings");13 while((str=in.readLine())!=null){14 while(m.find()){15 System.out.println(m.group());16 }17 int i=0;18 while(m.find(i)){19 System.out.print(m.group()+" ");20 i++;21 }22 }23 in.close();24 }25 }
View Code
输出结果为:
Evening
is
full
of
the
linnet
s
Evening vening ening ning ing ng g is is s full full ull ll l of of f the the he e linnet linnet innet nnet net et t s s
原文是:"Evening","is","full","of","the","linnet","s","wings",
"Eveing vening ening ning ing ng g is is a full full ull ll l of of f the the the he e linnet linnet innet nnet net et t s s wings wings ings ngs gs s a"
"\\w+"的意思是“一个或多个单词字符”,因此它将会将字符串直接分解成单词。find()像一个迭代器,从头到尾扫描一遍字符串。而第二个find()是带int参数的,它将会告诉你,从那个位置开始查找--从参数的位置开始查找。
Groups
Group是指里用括号括起来的,能被后面的表达式调用的正则表达式。Group 0表示整个表达式,group 1表示第一个被括起来的group,以次类推。比如:
A(B(C))D 有三个group:group 0是ABCD,gourp 1是BC,group 2是C。
这是一些常用的grou方法:
public int groupCount()返回matcher对象中的group的数目。不包括group 0
public String group()返回上次匹配操作(比方说find()的group 0(整个匹配))
public String group(int i)返回上次匹配操作的某个group。如果成功,但是没找到group,返回null。
public int start(int group)返回上次匹配所找到的,group的开始位置。
public int end(int group)返回上次匹配所找到的,group的结束位置,最后一个字符的下标。
1 packageperl;2 import java.util.regex.*;3 import java.io.*;4 public classtest1 {5 static public final String poem="Twas brillig, and the slithy toves/n" +
6 "Did gyre and gimble in the wabe./n" +
7 "All mimsy were the borogoves,/n" +
8 "And the mome raths outgrabe./n/n" +
9 "Beware the Jabberwock, my son,/n" +
10 "The jaws that bite, the claws that catch./n" +
11 "Beware the Jubjub bird, and shun/n" +
12 "The frumious Bandersnatch.";13 public static void main(String[] args) throwsIOException{14 //BufferedReader in;15 //in=new BufferedReader(new FileReader("C:/Users/liuzhongfeng/Desktop/文件/java/find1.txt"));
16 Matcher m=Pattern.compile("(?m)(\\S+)\\s+((\\S+)\\s+(\\S+))").matcher(poem);17 //while(in.readLine()!=null){
18 while(m.find()){//查找是否有单个单词匹配,有则输出
19 for(int j=0;j<=m.groupCount();j++){20 System.out.println("["+m.group(j)+"]");21 }22 System.out.println();23 }24 //}25 //in.close();
26 }27 }
View Code
结果是:
[Twas brillig, and]
[Twas]
[brillig, and]
[brillig,]
[and]
[the slithy toves/nDid]
[the]
[slithy toves/nDid]
[slithy]
[toves/nDid]
[gyre and gimble]
[gyre]
[and gimble]
[and]
[gimble]
[in the wabe./nAll]
[in]
[the wabe./nAll]
[the]
[wabe./nAll]
[mimsy were the]
[mimsy]
[were the]
[were]
[the]
[borogoves,/nAnd the mome]
[borogoves,/nAnd]
[the mome]
[the]
[mome]
[raths outgrabe./n/nBeware the]
[raths]
[outgrabe./n/nBeware the]
[outgrabe./n/nBeware]
[the]
[Jabberwock, my son,/nThe]
[Jabberwock,]
[my son,/nThe]
[my]
[son,/nThe]
[jaws that bite,]
[jaws]
[that bite,]
[that]
[bite,]
[the claws that]
[the]
[claws that]
[claws]
[that]
[catch./nBeware the Jubjub]
[catch./nBeware]
[the Jubjub]
[the]
[Jubjub]
[bird, and shun/nThe]
[bird,]
[and shun/nThe]
[and]
[shun/nThe]
View Code
这首诗是Through the Looking Glass的,Lewis Carroll的"Jabberwocky"的第一部分。可以看到这个正则表达式里有很多用括号括起来的group,它是由任意多个连续的非空字符('/S+')和任意多个连续的空格字符('/s+')所组成的,其最终目的是要捕获每行的最后三个单词;'$'表示一行的结尾。但是'$'通常表示整个字符串的结尾,所以这里要明确地告诉正则表达式注意换行符。这一点是由'(?m)'标志完成的(模式标志会过一会讲解)。
start()和end()
如果匹配成功,start返回匹配开始的位置,end()返回匹配结束的位置,即最后一个字符的下标加一。如果之前的匹配不成功(或者没匹配),那么无论是调用start( )还是end( ),都会引发一个IllegalStateException。下面这段程序还演示了matches( )和lookingAt( ):
1 packageperl;2 import java.io.*;3 import java.util.regex.*;4 public classtest2 {5 public static void main(String[] args) throwsIOException{6 String[] input=new String[]{"Java has regular expressions in 1.4",7 "regular expressions now expressing in Java",8 "Java represses oracular expressions"};9 Pattern p1=Pattern.compile("re\\w*"),p2=Pattern.compile("Java.*");10 for(int i=0;i
20 System.out.println("m1.lookingAt() start= "+m1.start()+"end= "+m1.end());21 }22 if(m2.lookingAt()){23 System.out.println("m2.lookingAt() start= "+m2.start()+"end= "+m2.end());24 }25 if(m1.matches()){//No reset() necessary
26 System.out.println("m1.matches() start= "+m1.start()+"end= "+m1.end());27 }28 if(m2.matches()){29 System.out.println("m2.matches() start= "+m2.start()+"end= "+m2.end());30 }31 }32 }33
34
35 }
View Code
结果为:
input 0: Java has regular expressions in 1.4m1.find()'regularstart=9end=16
m1.find() 'ressionsstart=20end=28
m2.find() 'Java has regular expressions in 1.4start=0end=35
m2.lookingAt() start= 0end= 35m2.matches() start= 0end= 35input1: regular expressions now expressing in Java
m1.find()'regularstart=0end=7
m1.find() 'ressionsstart=11end=19
m1.find() 'ressingstart=27end=34
m2.find() 'Javastart=38end=42
m1.lookingAt() start= 0end= 7input2: Java represses oracular expressions
m1.find()'repressesstart=5end=14
m1.find() 'ressionsstart=27end=35
m2.find() 'Java represses oracular expressionsstart=0end=35
m2.lookingAt() start= 0end= 35m2.matches() start= 0end= 35
View Code
注意,只要字符串有这个模式,find()就能把它找出来,但是lookingAt()和matches(),只有在字符串与正则表达式一开始就匹配的情况下才能返回true,matches()成功的前提是正则表达式必须与字符串完全匹配,而lookingAt()前提是,字符串的开始部分与正则表达式相匹配。匹配的模式(Pattern flags)
compile()方法还有一个版本,它需要一个控制正则表达式的匹配行为的参数:
Pattern Pattern.compile(String regex,int flag)
编译标志: 效果:
Pattern.CANON_EQ 当且仅当两个字符的"正规分解(canonical decomposition)"都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a/u030A"会匹配"?"。
默认情况下,不考虑"规范相等性(canonical equivalence)"。
Pattern.CASE_INSENSITIVE(?i) 默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。
这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹配,
只要将UNICODE_CASE与这个标志合起来就行了。
Pattern.COMMENTS(?x) 在这种模式下,匹配时会忽略(正则表达式里的)空格字符(注:不是指表达式里的"//s",
而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。
可以通过嵌入式的标志来启用Unix行模式。
Pattern.DOTALL(?s) 在这种模式下,表达式'.'可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式'.'不匹配行的结束符。
Pattern.MULTILINE(?m) 在这种模式下,'^'和'$'分别匹配一行的开始和结束。此外,'^'仍然匹配字符串的开始,'$'也匹配字符串的结束。
默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
Pattern.UNICODE_CASE(?u) 在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配。
默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。
Pattern.UNIX_LINES(?d) 在这个模式下,只有'/n'才被认作一行的中止,并且与'.','^',以及'$'进行匹配
View Code
在这些标志里面,Pattern.CASE_INSENSITIVE,Pattern.MULTILINE,以及Pattern.COMMENTS是最有用的(其中Pattern.COMMENTS还能帮我们把思路理清楚,并且/或者做文档)。注意,你可以用在表达式里插记号的方式来启用绝大多数的模式。这些记号就在上面那张表的各个标志的下面。你希望模式从哪里开始启动,就在哪里插记号。
可以用"OR" ('|')运算符把这些标志合使用:
1 packageperl;2
3 import java.util.regex.*;4
5 public classTest3 {6 public static voidmain(String[] args){7 String[] in=new String[]{"java has regular expressions in 1.4",8 "regular expressions now expressing in Java",9 "Java represses oracular expressions"};10 Pattern p=Pattern.compile("^java",Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);11 for(int i=0;i
View Code
结果为:
java
Java
split()
所谓分割是指将以正则表达式为界,将字符串分割成String数组。方法:
String[] split(CharSequence charseq)
String[] split(CharSequence charseq,int limit)
这是一种既快又方便地将文本根据一些常见的边界标志分割开来的方法。
替换操作
正则表达式在替换文本方面特别在行。下面就是一些方法:
replaceFirst(String replacement)将字符串里,第一个与模式相匹配的子串替换成replacement。
replaceAll(String replacement),将输入字符串里所有与模式相匹配的子串全部替换成replacement
appendReplacement(StringBuffer sbuf, String replacement)对sbuf进行逐次替换,而不是像replaceFirst( )或replaceAll( )那样,只替换第一个或全部子串。这是个非常重要的方法,因为它可以调用方法来生成replacement(replaceFirst( )和replaceAll( )只允许用固定的字符串来充当replacement)。有了这个方法,你就可以编程区分group,从而实现更强大的替换功能。
调用完appendReplacement( )之后,为了把剩余的字符串拷贝回去,必须调用appendTail(StringBuffer sbuf, String replacement)。
1 packageperl;2
3 import java.util.regex.*;4
5 public classtest5 {6 public static voidmain(String[] args){7 String s="/*! Here's a block of text to use as input to"+
8 "the regular expression matcher. Note that we'll"+
9 "first extract the block of text by looking for"+
10 "the special delimiters, then process the"+
11 "extracted block. !*/";12 Matcher mInput=Pattern.compile("\\/*!(.*)!\\*/",Pattern.DOTALL).matcher(s);13 if(mInput.find())14 s=mInput.group(1);15 s=s.replaceAll(" {2,}"," ");16 s=s.replaceAll("(?m)^ +","");17 System.out.println(s);18 s=s.replaceFirst("[aeiou]", "(VOWEL1)");//只是替换aeiou第一个出现的,
19 StringBuffer sbuf=newStringBuffer();20 Pattern p=Pattern.compile("[aeiou]");21 Matcher m=p.matcher(s);22 while(m.find()){23 m.appendReplacement(sbuf, m.group().toUpperCase());24 }//把小写的aeiou全部替换成大写
25 m.appendTail(sbuf);26 System.out.println(sbuf);27 }28 }
View Code
结果为:
Here's a block of text to use as input tothe regular expression matcher. Note that we'llfirst extract the block of text by looking forthe special delimiters, then process theextracted block.
H(VOWEL1)rE's A blOck Of tExt tO UsE As InpUt tOthE rEgUlAr ExprEssIOn mAtchEr. NOtE thAt wE'llfIrst ExtrAct thE blOck Of tExt by lOOkIng fOrthE spEcIAl dElImItErs, thEn prOcEss thEExtrActEd blOck.
View Code
replaceFirst( )只替换第一个子串。此外,replaceFirst( )和replaceAll( )只能用常量(literal)来替换,所以如果每次替换的时候还要进行一些操作的话,它们是无能为力的。碰到这种情况,得用appendReplacement( ),它能在进行替换的时候想写多少代码就写多少。在上面那段程序里,创建sbuf的过程就是选group做处理,也就是用正则表达式把元音字母找出来,然后换成大写的过程。通常你得在完成全部的替换之后才调用appendTail( ),但是如果要模仿replaceFirst( )(或"replace n")的效果,你也可以只替换一次就调用appendTail( )。它会把剩下的东西全都放进sbuf。
reset()
此外,还可以用reset( )方法给现有的Matcher对象配上个新的CharSequence。
1 packageperl;2
3 import java.util.regex.*;4
5 public classtest6 {6 public static voidmain(String[] args){7 Matcher m=Pattern.compile("[frb][aiu][gx]").matcher("fix the rug with bags");8 System.out.print("原来的 结果:");9 while(m.find())10 System.out.print(m.group()+" ");11 System.out.println();12 System.out.print("后来的reset结果:");13 m.reset("fix the rig with rags");14 while(m.find())15 System.out.print(m.group()+" ");16 }17 }
View Code
结果为:
原来的 结果:fix rug bag
后来的reset结果:fix rig rag
三、应用实例
3.1 日志文件处理
任务:分析一个Web服务器的日志文件,确定每一个用户花在网站上的时间。格式如下:
172.26.155.241 - - [26/Feb/2001:10:56:03 -0500]
"GET /sAlive.htm HTTP/1.0" 200 15
要从这个日志文件提取的内容有两项:IP地址和页面访问时间。可以用分组符号(圆括号)从日志记录提取出IP地址和时间标记。
(\d{1,3}\.\d{1.3}\.d{1,3}\.\d{1,3})\s-\s\-\s \[([^]]+)\]
3.2 HTML处理实例一
下面一个任务是分析HTML页面内FONT标记的所有属性。HTML页面内典型的FONT标记如下所示:
程序将按照如下形式,输出每一个FONT标记的属性:
采取步骤:先提取出“"face="Arial, Serif" size="+2" color="red"”。
< \s* font \s* ([^>]*) \s* >
然后提取第二个正则表达式:
([a-z]+) \s* = \s* " ([^"]+) "
分割的结果为:
3.3 HTML处理实例二
我们假定Web服务器从widgets.acme.com移到了newserver.acme.com。现在你要修改一些页面中的链接:
首先匹配修改前的链接:
如果能够匹配这个正则表达式,你可以用下面的内容替换上边的链接:
3.4一个检验Email地址的小程序
该程序是用来检验一个输入的EMAIL地址里所包含的字符是否合法,虽然这不是一个完整的EMAIL地址检验程序,它不能检验所有可能出现的情况,但在必要时您可以在其基础上增加所需功能。
1 packageperl;2
3 import java.util.*;4 import java.util.regex.*;5
6 public classtest7 {7 public static voidmain(String[] args){8 System.out.println("请输入EMALL地址:");9 Scanner in = newScanner(System.in);10 String input =in.next();11 //检测输入的EMAIL地址是否以 非法符号"."或"@"作为起始字符
12 Pattern p=Pattern.compile("^\\.|^\\@");13 Matcher m=p.matcher(input);14 if(m.find()){15 System.out.println("EMAIL地址不能以'.'或'@'作为起始字符");16 }17 Pattern p1=Pattern.compile("^www\\.");18 Matcher m1=p1.matcher(input);19 if(m1.find()){20 System.out.println("EMAIL地址不能以'www.'起始");21 }22
23 Pattern p2=Pattern.compile("[A-Za-z0-9\\.\\@_\\-~#]+");24 Matcher m2=p2.matcher(input);25 StringBuffer sb=newStringBuffer();26 boolean result=m2.find();27 boolean deletedIllegalChars=false;28 while(result){//如果找到了非法字符那么就设下标记
29 deletedIllegalChars=true;30 //如果里面包含非法字符如冒号双引号等,那么就把他们消去,加到SB里面
31 m2.appendReplacement(sb, "");32 result=m2.find();33 }34 m2.appendTail(sb);35 if(deletedIllegalChars){36 System.out.println("输入的EMALL地址包含有冒号,都好等非法字符,请重新输入");37 }38 }39
40 }
View Code