Java 中正则表达式的应用 ( 一 )
有一点需要清楚的是,如果你把构造器 Perl5Substitution(java.lang.String substitution,int numInterpolations)
中的 numInterpolations 参数设为 INTERPOLATE_ALL,那么当每次找到一个匹配字串时,替换变量($1,$2 等)所指向的内容都根据目前匹配字串来更新,但是如果 numInterpolations 参数设为一个正整数 N 时,那么在替换时就只会在前 N 次匹配发生时替换变量会跟随匹配对象来调整所代表的内容,但 N 次之后就以一致以第 N 次替换变量所代表内容来做为以后替换结果。
举个例子会更好理解:
假如沿用以上例子中的正则表达式模式以及替换内容来进行替换工作,设目标字符串为"Tank b123: 85 Tank b256: 32 Tank b78: 22",并且设 numInterpolations 参数为 INTERPOLATE_ALL,而 Util.substitute() 方法中的 numSub 变量设为 SUBSTITUTE_ALL(请参考上文 Util.substitute() 方法内容),那么你获得的替换结果将会是:?Tank a123- 85 Tank a256- 32 Tank a78- 22
但是如果你把 numInterpolations 设为 2,并且 numSubs 依然设为 SUBSTITUTE_ALL,那么这时你获得的结果则会是:?Tank a123- 85 Tank a256- 32 Tank a256- 22
你要注意到最后一个替换所用变量 $1 所代表的内容与第二个 $1 一样为"256",而不是预期的"78",因为在替换进行中,替换变量 $1 只根据匹配内容进行了两次更新,最后一次就使第二次匹配时所更新的结果,那么我们可以由此知道,如果 numInterpolations 设为 1,那么结果将是:?Tank a123- 85 Tank a123- 32 Tank a123- 22
并且在表达式里每个符号中间不能有空格,否则就会同样出现编译错误。
PatternCompiler compiler=new Perl5Compiler();
Pattern pattern=compiler.compile(restring);
输出结果为:kevin 的音标为 ['kevin]
在这个处理中我是用 toString() 方法来取得结果,但是如果正则表达式里是用了分组符号(圆括号),那么就可以用 group(int gid) 的方法来取得相应各组匹配的结果,如正则表达式改为" (\[[^]]+\])",那么就可以用以下方法来取得结果:pure=result.group(0);
用程序验证,输出结果同样为:kevin 的音标为 ['kevin]
而如果正则表达式为(\[[^]]+\])(\[[^]]+\]),则会查找到两个连续的方括号所包含的内容,也就找到 [ 音标 ] [ 词性 ] 两项,但是两项的结果分别在两个组里面,分别由下面语句获得结果:
result.group(0)-> 返回 [ 音标 ] [ 词性 ] 两项内容,也就是与整个正则表达式相匹配的结果字符串,在这里也就为 ['kevin] [ 名词 ]
result.group(1) -> 返回 [ 音标 ] 项内容,结果应是 ['kevin]
result.group(2) -> 返回 [ 词性 ] 项内容,结果应是 [ 名词 ]
继续用程序验证,发现输出并不正确,主要是当内容有中文时就不能成功匹配,考虑到可能是 Jakarta-ORO 正则表达式库版本不支持中文的问题,回看一下原来我一直用的还是 2.0.1 的老版本,马上到 Jakarta.org 上下载最新的 2.0.4 版本装上再用程序验证,得出的结果就和预期一样正确。
★查找多个匹配:?
经过第一步的尝试使用 Jakarta-ORO 后,我们已经知道了如何正确使用该 API 包来查找目标字符串里一个匹配的子串,下面我们接着来看一看当目标字符串里包含不止一个匹配的子串时我们如何把它们一个接一个找出来进行相应的处理。
首先我们先试个简单的应用,假设我们想把 CONTNET 字段内容里所有用方括号包起来的字串都找出来,很清楚地,CONTNET 字段的内容里面就只有两项匹配的内容:[ 音标 ] 和 [ 词性 ],刚才我们其实已经把它们分别找出来了,但是我们所用的方法是分组方法,把"[ 音标 ] [ 词性 ]"作为一整个正则表达式匹配的内容先找到,再根据分组把 [ 音标 ] 和 [ 词性 ] 分别挑出来。但是现在我们需要做的是把 [ 音标 ] 和 [ 词性 ] 分别做为与同一个正则表达式匹配的内容,先找到一个接着再找下一个,也就是刚才我们的表达式为(\[[^]]+\])(\[[^]]+\]), 而现在应为" \[[^]]+\] "。
我们已经知道在匹配操作的三个方法里只要用 PatternMatcherInput 对象作为参数替代 String 对象就可以从字符串中最后一次匹配的位置开始继续进行匹配,实现的程序片段如下:
为了简便起见,我们不再和从数据库里读出,而是构造一个包含同样内容的字符串变量,程序片段如下:
?
输出结果为:?
英文句 : Kevin loves comic.?
句子中文翻译 : 凯文爱漫画?
词性 : 名词?
意思 : 凯文?
英文句 : Kevin is living in ZhuHai now.?
句子中文翻译 : 凯文现住在珠海?
词性 : 名词?
意思 : 凯文
★查找替换:?
以上的两个应用都是单纯在查找字符串匹配方面的,我们再来看一下查找后如何对目标字符串进行替换。
例如我现在想把第二个例句进行改动,换为:Kevin has seen 《 LEON 》 seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。/ 名词 : 凯文。
也就是把?
['kevin] [ 名词 ](人名凯文){(Kevin loves comic./ 凯文爱漫画 / 名词 : 凯文 )( Kevin is living in ZhuHai now. / 凯文现住在珠海 / 名词 : 凯文 )}
改为:?
['kevin] [ 名词 ](人名凯文){(Kevin loves comic./ 凯文爱漫画 / 名词 : 凯文 )( Kevin has seen 《 LEON 》 seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。/ 名词 : 凯文。)}
之前,我们已经了解 Util.substitute() 方法与 Substiution 接口,以及 Substiution 的两个实现类 StringSubstitution 和 Perl5Substitution,我们就来看看怎么用 Util.substitute() 方法配合 Perl5Substitution 来完成我们上面提出的替换要求,确定正则表达式:
我们要先找到其中的整个例句部分,也就是由大括号包起来的字串,并且把两个例句分别分组,所以正则表达式为:"\{(\([^)]+\))(\([^)]+\))\}",如果用替换变量来代替分组,那么上面的表达式可以看为"\{$1$2\}", 这样就可以更容易看出替换变量与分组间的关系。
根据上面的正则表达式 Perl5Substitution 类可以这样构造: Perl5Substitution("{$1( Kevin has seen 《 LEON 》 seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。/ 名词 : 凯文。)}")
再根据这个 Perl5Substitution 对象来使用 Util.substitute() 方法便可以完成替换了,实现的代码片段如下:
总结:本文首先介绍了 Jakarta-ORO 正则表达式库的对象与方法,并且接着举例让读者对实际应用有进一步的了解,虽然例子都比较简单,但希望读者们在看了该文后对 Jakarta-ORO 正则表达式库有一定的认知,在实际工作中有所帮助与启发。
?