日历
网志分类
· 所有网志 (11)
· 水牛小屋 (4)
· 算法学习 (2)
· ACM/ICPC (3)
· 未分类 (2)
最新的评论
站内搜索
友情链接
· ZJU
· HDU
· PKU
· TC
· UVA
· SPOJ
· SGU
· URAL
· EL
· ProjectEuler
· Mathpuzzle
· CodeProject
· Algorithmist

订阅 RSS

0001523

歪酷博客

saintqdd

大家好,欢迎光临本博客(OIer,ACMer or coder,...)
mail: saintqdd@gmail.com  saintqdd@hotmail.com


saint623 @ 2008-08-13 09:13

java.util.regex的帮助文档 
Dana Nourie 
Mike McCloskey所写的Regular Expressions and the Java™ Programming Language 
需要更多的第三方正则表达式资源以及基于它们所开发的应用程序请看http://www.meurrens.org/ip-Links/java/regex/index.html 
Java's java.util.regex 包包括:Pattern类、Matcher类、MatchResult接口和PatternSyntaxException异常:
  • Pattern 对象代表了编译了的正则表达式(A compiled representation of a regular expression.)。
  • Matcher An engine that performs match operations on a character sequence by interpreting a Pattern.
  • MatchResult接口:The result of a match operation.
  • PatternSyntaxException对象,描述非法的regex patternsUnchecked exception thrown to indicate a syntax error in a regular-expression pattern.
 同时还需要了解是CharSequenceJDK 1.4定义的新的接口,它提供了StringStringBuffer这两个类的字符序列的抽象
interface CharSequence {
 charAt(int i);
 length();
 subSequence(int start, int end);
 toString();
}
为了实现这个新的CharSequence接口,StringStringBuffer以及CharBuffer都作了修改,很多的正则表达式的操作都要拿CharSequence作参数。
Matcher类的几个重要的方法:
  • boolean matches()Pattern匹配整个字符串
  • boolean lookingAt()Pattern匹配字符串的开头
  • boolean find():发现CharSequence里的,与pattern相匹配的多个字符序列
    boolean find(int start)
    :告诉方法从参数start位置开始查找
group的概念
Group是指里用括号括起来的,能被后面的表达式调用的正则表达式。
Group 0 表示整个表达式,group 1表示第一个被括起来的group,以此类推。所以;
A(B(C))D
里面有三个groupgroup 0ABCD group 1BCgroup 2C
你可以用下述Matcher方法来使用group
  • public int groupCount( )返回matcher对象中的group的数目。不包括group0
  • 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的结束位置,最后一个字符的下标加一。
  • split( ) 是指将以正则表达式为界,将字符串分割成String数组,如果带有limit参数,split( )会限定分割的次数。
  • 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)
 
使用group可以做到逐步缩小匹配的范围,直至精确匹配的目的。
start( )end( ):如果匹配成功,start( )会返回此次匹配的开始位置,end( )会返回此次匹配的结束位置,即最后一个字符的下标加一。如果之前的匹配不成功(或者没匹配),那么无论是调用start( )还是end( ),都会引发一个IllegalStateException
二、4大使用方法:
查询
String str="abc efg ABC";
String regEx="a|f"; //表示af
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
boolean rs=m.find();
如果str中有regEx,那么rstrue,否则为flase。如果想在查找时忽略大小写,则可以写成Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
提取
String regEx=".+\(.+)$";
String str="c:\dir1\dir2\name.txt";
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
boolean rs=m.find();
for(int i=1;i<=m.groupCount();i++){
System.out.println(m.group(i));
}
以上的执行结果为name.txt,提取的字符串储存在m.group(i)中,其中i最大值为m.groupCount();
 
分割
String regEx="::";
Pattern p=Pattern.compile(regEx);
String[] r=p.split("xd::abc::cde");
执行后,r就是{"xd","abc","cde"},其实分割时还有跟简单的方法:
String str="xd::abc::cde";
String[] r=str.split("::");
 
替换或者删除
String regEx="a+"; //表示一个或多个a
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher("aaabbced a ccdeaa");
String s=m.replaceAll("A");
  结果为"Abbced A ccdeA"
  如果写成空串,既可达到删除的功能,比如:
String s=m.replaceAll("");
  结果为"bbced ccde"
 
三、一个实际的例子
下面的函数是一个实际应用的例子,需求是需要将抓取的网页中的<img src=''http://aa.bb.cc.com/images/**.jpg"> 中的地址,保存到一个地址列表中(以供抓取图片使用),并将绝对地址替换成本地的相对地址,即<img src="images/**.jpg">
public static Map<String, String> getImagesURL(String description) {
      Map<String, String> map = new HashMap<String, String>();
        // img
的正则表达式:匹配<img>标签       
        String imgPattern = "<\s*img\s+([^>]+)\s*>";
        Pattern pattern1 = Pattern.compile(imgPattern, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern1.matcher(description);
        // img src元素的正则表达式:匹配img标签内的src属性
        String srcPattern = "\s*src\s*=\s*\"([^\"]+)\s*\"";
        Pattern pattern2 = Pattern.compile(srcPattern, Pattern.CASE_INSENSITIVE);
        while (matcher.find()) {
           //group()返回符合表达式的内容
            Matcher matcher2 = pattern2 .matcher(matcher.group());
            //
一定要find(),这是实际的匹配动作
            if (matcher2.find()) {
                String src = matcher2.group();
                log.info(src);
                int i2 = src.lastIndexOf('/');
                int i1 = src.indexOf("http");
                if (i1 != -1) {
                    map.put(src.substring(i2 + 1, src.length() - 1), src
                            .substring(i1, src.length() - 1));
                }
            }
        }
        log.debug("
图片:" + map);
        return map;
    }
 
整体思路是先匹配到img标签,然后匹配src属性,并修改src的属性
"<\s*img\s+([^>]+)\s*>" 的解释:
\s* :0 或多个空格   \s+: 至少一个空格
([^>]+):指的是到>为止的所有的元素,至少一个
 
常用的正则表达式(参考jdkregex文档)
字符集类
.                            表示任意一个字符
[abc]                     表示字符abc中的任意一个(a|b|c相同)
[^abc]                   abc之外的任意一个字符(否定)
[a-zA-Z]                azAZ当中的任意一个字符(范围)
[abc[hij]]              a,b,c,h,i,j中的任意一个字符(a|b|c|h|i|j相同)(并集)
[a-z&&[hij]]          h,i,j中的一个(交集)
\s                          空格字符(空格键, tab, 换行, 换页, 回车)
\S                         非空格字符([^\s])
\d                         一个数字,也就是[0-9]
\D                         一个非数字的字符,也就是[^0-9]
\w                        一个单词字符(word character),即[a-zA-Z_0-9]
\W                       一个非单词的字符,[^\w]
字符类:
B                         字符B
\xhh                    16进制值0xhh所表示的字符
\uhhhh                16进制值0xhhhh所表示的Unicode字符
\t                         Tab
\n                        换行符
\r                         回车符
\f                        换页符
\e                       Escape
逻辑运算符
XY                      X 后面跟着 Y
X|Y                    XY
(X)                     一个"要匹配的组(capturing group)". 以后可以用\i来表示第i个被匹配的组。
边界匹配符
^                      一行的开始
$                      一行的结尾
\b                    一个单词的边界
\B                    一个非单词的边界
\G                   前一个匹配的结束
数量表示符
"数量表示符(quantifier)"的作用是定义模式应该匹配多少个字符。
  • Greedy(贪婪的)除非另有表示,否则数量表示符都是greedy的。Greedy的表达式会一直匹配下去,直到匹配不下去为止。(如果你发现表达式匹配的结果与预期的不符),很有可能是因为,你以为表达式会只匹配前面几个字符,而实际上它是greedy的,因此会一直匹配下去。
  • Reluctant(勉强的)用问号表示,它会匹配最少的字符。也称为lazy, minimal matching, non-greedy, ungreedy
  • Possessive(占有的)目前只有Java支持(其它语言都不支持)。它更加先进,所以你可能还不太会用。用正则表达式匹配字符串的时候会产生很多中间状态,(一般的匹配引擎会保存这种中间状态,)这样匹配失败的时候就能原路返回了。占有型的表达式不保存这种中间状态,因此也就不会回头重来了。它能防止正则表达式的失控,同时也能提高运行的效率。
Greedy                    Reluctant                           Possessive                      匹配
X?                            X??                                      X?+                                  匹配一个或零个X
X*                            X*?                                      X*+                                  匹配零或多个X
X+                           X+?                                      X++                                 匹配一个或多个X
X{n}                        X{n}?                                   X{n}+                               匹配正好nX
X{n,}                       X{n,}?                                 X{n,}+                              匹配至少nX
X{n,m}                   X{n,m}?                                X{n,m}+                           匹配至少n个,至多mX
参考资料
要想进一步学习正则表达式,建议看Mastering Regular Expression, 2nd Edition,作者Jeffrey E. F. Friedl (O’Reilly, 2002)
"Regular Expressions and the Java Programming Language," Dana Nourie and Mike McCloskey (Sun Microsystems, August 2002) presents a brief overview of java.util.regex, including five illustrative regex-based applications:
http://developer.java.sun.com/developer/technicalArticles/releases/1.4regex/