挨踢step by step

宁可挨踢,不可露怯。知耻而后勇!

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  0 Posts :: 6 Stories :: 0 Comments :: 0 Trackbacks

§ 1 黑暗岁月

       有一个 String ,如何查询其中是否有 y f 字符?最黑暗的办法就是:

程序 1 :我知道 if for 语句和 charAt() 啊。

class Test{

  public static void main(String args[]) {

         String str="For my money, the important thing "+

         "about the meeting was bridge-building";

         char x='y';

         char y='f';

         boolean result=false;

         for(int i=0;i<str.length();i++){

                char z=str.charAt(i);  //System.out.println(z);

                if(x==z||y==z) {

                       result=true;

                       break;

                }

                else result=false;

         } 

         System.out.println(result);

       }

}

       好像很直观,但这种方式难以应付复杂的工作。如查询一段文字中,是否有 is ?是否有 thing ting 等。这是一个讨厌的工作。

§ 2 Java java.util.regex

       按照面向对象的思路,把希望查询的字符串如 is thing ting 封装成一个对象,以这个对象作为模板去匹配一段文字,就更加自然了。作为模板的那个东西就是下面要讨论的正则表达式。先不考虑那么复杂,看一个例子:

程序 2 :不懂。先看看可以吧?

import java.util.regex.*;

class Regex1{

  public static void main(String args[]) {

         String str="For my money, the important thing "+

         "about the meeting was bridge-building";

         String regEx="a|f";   // 表示 a f

         Pattern p=Pattern.compile(regEx);

         Matcher m=p.matcher(str);

         boolean result=m.find();

         System.out.println(result);

       }

}

       如果 str 匹配 regEx ,那么 result true ,否则为 flase 。如果想在查找时忽略大小写,则可以写成:

Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);

       虽然暂时不知道 Pattern (模板、模式)和 Matcher (匹配器)的细节,程序的感觉就比较爽,如果先查询 is 、后来又要查询 thing ting ,我们只需要修改一下模板 Pattern ,而不是考虑 if 语句和 for 语句,或者通过 charAt()

1、 写一个特殊的字符串——正则表达式如 a|f

2、 将正则表达式编译成一个模板: p

3、 用模板 p 去匹配字符串 str

       思路清楚了,现在看 Java 是如何处理的( Java 程序员直到 JDK1.4 才能使用这些类。

§ 3 Pattern 类与查找

       public final class java.util.regex.Pattern 正则表达式编译后的表达法。下面的语句将创建一个 Pattern 对象并赋值给句柄 p Pattern p=Pattern.compile(regEx);

       有趣的是, Pattern 类是 final 类,而且它的构造器是 private 。也许有人告诉你一些设计模式的东西,或者你自己查有关资料。这里的结论是: Pattern 类不能被继承,我们不能通过 new 创建 Pattern 类的对象。

       因此在 Pattern 类中,提供了 2 个重载的静态方法,其返回值是 Pattern 对象(的引用)。如:

    public static Pattern compile(String regex) {

        return new Pattern(regex, 0);

    }

       当然,我们可以声明 Pattern 类的句柄,如 Pattern p=null

       p.matcher(str) 表示以用模板 p 去生成一个字符串 str 的匹配器,它的返回值是一个 Matcher 类的引用,为什么要这个东西呢?按照自然的想法,返回一个 boolean 值不行吗?

       我们可以简单的使用如下方法:

       boolean result=Pattern.compile(regEx).matcher(str).find();

       呵呵,其实是三个语句合并的无句柄方式。无句柄常常不是好方式。后面再学习 Matcher 类吧。先看看 regEx ——这个怪咚咚。

§ 4 正则表达式之限定符

       正则表达式( Regular Expression 是一种生成字符串的字符串。晕吧。比如说, String regEx="me+"; 这里字符串 me+ 能够生成的字符串是: me mee meee meeeeeeeeee 等等,一个正则表达式可能生成无穷的字符串,所以我们不可能(有必要吗?)输出正则表达式产生的所有东西。

反过来考虑,对于字符串: me mee meee meeeeeeeeee 等等,我们能否有一种语言去描述它们呢?显然,正则表达式语言是这种语言,它是一些字符串的模式——简洁而深刻的描述。

我们使用正则表达式,用于字符串查找、匹配、指定字符串替换、字符串分割等等目的。

 

       生成字符串的字符串——正则表达式,真有些复杂,因为我们希望 由普通字符(例如字符 a z )以及特殊字符(称为元字符) 描述 任意的字符串,而且要准确。

       先搞几个 正则表达式 例子:

       程序 3 :我们总用这个程序测试正则表达式。

       import java.util.regex.*;

class Regex1{

  public static void main(String args[]) {

         String str="For my money, the important thing "

         String regEx="ab*";

         boolean result=Pattern.compile(regEx).matcher(str).find();

         System.out.println(result);

       }

}//ture

"ab*" ——能匹配 a ab abb abbb ……。所以, * 表示前面字符可以有零次或多次。如果仅仅考虑查找,直接用 "a" 也一样。但想想替换的情况。 问题 regEx="abb*" 结果如何?

"ab+" ——能匹配 ab abb abbb ……。等价于 "abb*" 问题 regEx="or+" 结果如何?

"or?" ——能匹配 o or ? 表示前面字符可以有零次或一次。

       这些限定符 * + ? 方便地表示了其前面字符 ( 子串 ) 出现的次数(我们用 {} 来描述):

x*

零次或多次 ≡{0,}

x+

一次或多次 ≡{1,}

x?

零次或一次 ≡{0,1}

x{n}

n 次( n>0

x{n,m}

最少 n 次至最多 m 次( 0<n<m

x{n,}

最少 n ,

      

现在我们知道了连续字符串的查找、匹配。下面的是一些练习题:

①查找粗体字符串(不要求精确或要求精确匹配),写出其正则表达式:

str

regEX( 不要求精确 )

regEX( 要求精确 )

试一试

abcffd

b bcff bcf* bc* bc+

bcff bcf{2}

bc{3}

gooooogle

o{1,} o+

o{5}

 

banana

(an)+

(an){2}a a(na) {2}

 

 

 

 

 

 

 

 

 

 

 

 

 

②正则表达式匹配字符串,输出是什么?

§ 5 替换(删除)、 Matcher

现在我们可能厌烦了 true/false ,我们看看替换。如把 book google 替换成 bak (这个文件后缀名,在 EditPlus 中还行)、 look goooogle

       程序 4 :字符串的替换。

       import java.util.regex.*;

class Regex1{

       public static void main(String args[]) {

              String regEx="a+";// 表示一个或多个 a

              String str="abbbaaa an banana hhaana";

              Pattern p=Pattern.compile(regEx);

              Matcher m=p.matcher(str);

              String s=m.replaceAll(" ⊙⊙ "); // ("") 删除

              System.out.println(s);

       }

}       

       这个程序与前面的程序的区别,在于使用了 m.replaceAll(String) 方法。看来 Matcher 类还有点用处。

    public final class Matcher 是一个匹配器。可以把他看成一个人,一手拿着模子( Pattern 类的对象),一手拿着一个字符序列( CharSequence ),通过解释该模子而对字符序列进行匹配操作( match operations )。常常我们这样编程:“喂,模子 p ,你和字符串 str 一起创建一个匹配器对象”。即 Matcher m=p.matcher(str);

    m 可以进行一些操作,如 public StringreplaceAll(String replacement) ,它以 replacement 替换所有匹配的字符串。

§ 6 正则表达式之特殊字符

我们熟悉这样一个字符串 "\n" 如: System.out.print(s+"\nbbb"); 这是 Java 中常用的转移字符之一。其实转移字符就是一种正则表达式,它使用了特殊字符 \

 

下面是正则表达式中常用的特殊字符:

匹配次数符号

*

+

{n} {n,} {n,m}

符号

|       程序 2 已经使用过了

句点符号

.       句点符号匹配所有字符(一个),包括空格、 Tab 字符甚至换行符。

方括号

[ ]    仅仅匹配方括号其中的字符 )

圆括号

()     分组,圆括号中的字符视为一个整体。

连字符

-      表示一个范围。

符号

^    表示不希望被匹配的字符(排除)

我们一下子学不了太多的东西,这不是正则表达式的全部内容和用法。但已经够我们忙活的了。我们用程序 4 验证。 ( ⊙⊙ 表示替换的字符 )

    regEx 为下列字符串时,能够表示什么?

regEx

匹配

测试用 str

(a|b){2}

aa ab bb ba

aabb fooaabfooabfoob

a[abc]b

aab abb acb

3dfacb5ooyfo6abbfooaab

.

all string

3dfac

a.

aa ax…… 等等

3dfacgg

d[^j]a

daa d9a 等等,除 dja

3dfacggdjad5a

[d-g][ac]c

dac ecc gac

3dfacggggccad5c

[d-g].{2}c

d ⊙⊙ c ……

3dfacggggccad5c

g{1,10}

g ggg ……

3dfacggggccad5c

[a|c][^a]

 

3dfacggggccad5c

 

    下列字符串如何用 regEx 表示?

测试用 str

匹配

regEx

aabb foaoabfooafobob

a ⊙⊙ b

a..b

aabbfoaaobfooafbob

a b 、除 aab

a[^a]b

gooooooogle

oooo ……变成 oo

o{2,20}

一本书中的 “tan” “ten” “tin” “ton”

t.n t[aeio]n

abcaccbcbaacabccaa

删除 ac ca

(ca)|(ac)

abccbcbaabca

再删除 ab ba

结果 ccbcca (如何与上面的合并)

 

 

 

 

 

 

 

 

 

注:

1 String str=" 一本书中的 tan ten tin ton";

输出:      一本书中的⊙⊙、⊙⊙、⊙⊙和⊙⊙

2 String str=" abcaccbcbaacabccaa "; 输出: ccbcca

       程序 5 if for 语句和 charAt() 886

import java.util.regex.*;

class Regex1{

    public static void main(String args[]) {

           String str="abcaccbcbaacabccaa";

           String regEx="(ac)|(ca)";

           Pattern p=Pattern.compile(regEx);

           Matcher m=p.matcher(str);

           String s=m.replaceAll("");// ⊙⊙

           regEx="(ab)|(ba)";

           p=Pattern.compile(regEx);

           s=p.matcher(s).replaceAll("");

 

           System.out.print(s+"\n");

    }

}

 

§ 7 开始

好像我们知道了一些 正则表达式与 Java 的知识,事实上,我们才刚刚开始。这里列出我们知道的东西,也说一点我们不知道的东西。

              Java JDK1.4 引入了( java.util.regex 包)以支持 正则表达式,包中有两个类,分别是 Pattern Matcher 。它们都有很多的方法,我们还不知道。 String 类中的 split matches 方法等等也使用到了 正则表达式。 StringTokenizer 是否没有用处了?

             正则表达式是一门语言。有许多正则表达式语法、选项和特殊字符,在 Pattern.java 源文件中大家可以查看。可能比想象中的要复杂。系统学习正则表达式的历史、语法、全部特殊字符(相当于 Java 中的关键字的地位),组合逻辑是下一步的事情。

             正则表达式是 文本处理的重要技术,在 Perl PHP Python JavaScript Java C #中被广泛支持。被列为“保证你现在和未来不失业的十种关键技术”,呵呵,信不信由你。

posted on 2006-11-09 14:10 AaronJin 阅读(124) 评论(0)  编辑  收藏 所属分类: Java转贴