天天看點

Java正規表達式學習(二)

Pattern & Matcher類

Pattern類

1.構造方法

Pattern類用于建立一個正規表達式,也可以說建立一個比對模式,它的構造方法是私有的,不可以直接建立,但可以通過

Pattern.complie(String regex)

簡單工廠方法(static 方法)建立一個正規表達式。例如:

package month12.day2.regex;
import java.util.regex.Pattern;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForPatternCompile {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("\\s");
        System.out.println(p.pattern());  //輸出\s
    }
}
           

重載方法:

public static Pattern compile(String regex, int flags)

關于flags的一些參數說明:

編譯标志 效果
Pattern.CANON_EQ 當且僅當兩個字元的”正規分解(canonical decomposition)”都完全相同的情況下,才認定比對。比如用了這個标志之後,表達式”a/u030A”會比對”?”。預設情況下,不考慮”規範相等性(canonical equivalence)”。
Pattern.CASE_INSENSITIVE 預設情況下,大小寫不敏感的比對隻适用于US-ASCII字元集。這個标志能讓表達式忽略大小寫進行比對。要想對Unicode字元進行大小不敏感的比對,隻要将UNICODE_CASE與這個标志合起來就行了。
Pattern.COMMENTS 在這種模式下,比對時會忽略(正規表達式裡的)空格字元(注:不是指表達式裡的”\s”,而是指表達式裡的空格,tab,回車之類)。注釋從#開始,一直到這行結束。可以通過嵌入式的标志來啟用Unix行模式。
Pattern.DOTALL 在這種模式下,表達式’.’可以比對任意字元,包括表示一行的結束符。預設情況下,表達式’.’不比對行的結束符。
Pattern.MULTILINE 在這種模式下,’^’和’$’分别比對一行的開始和結束。此外,’^’仍然比對字元串的開始,’$’也比對字元串的結束。預設情況下,這兩個表達式僅僅比對字元串的開始和結束。
Pattern.UNICODE_CASE 在這個模式下,如果你還啟用了CASE_INSENSITIVE标志,那麼它會對Unicode字元進行大小寫不明感的比對。預設情況下,大小寫不明感的比對隻适用于US-ASCII字元集。
Pattern.UNIX_LINES 在這個模式下,隻有’\n’才被認作一行的中止,并且與’.’,’^’,以及’$’進行比對。

pattern()

傳回正規表達式的字元串形式,其實就是傳回

Pattern.complile(String regex)

regex

參數

2.成員方法

1.public String[] split(CharSequence input)

Pattern有一個

split(CharSequence input)

方法,用于分隔字元串,并傳回一個String[],input為給定的字元串。例如:

package month12.day2.Pattern;

import java.util.regex.Pattern;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForSplit {
    public static void main(String args[]) {
        Pattern p = Pattern.compile("[,\\s]+");
        String str[] = p.split("我的QQ号碼是:1156405048  我的手機号是:17805938118" +
                                "   , 我的郵箱是[email protected]");
        for (int i = ; i < str.length; i++) {
            System.out.println(str[i]);
        }
    }
}
           

程式運作結果:

Java正規表達式學習(二)

重載方法:

public String[] split(CharSequence input, int limit)

,limit表示把目标字元串最多分割成幾段。

2.public static boolean matches(String regex, CharSequence input)

這是一個靜态方法,用于用于快速比對字元串,該方法适合用于隻比對一次,且比對全部字元串。例如:

package month12.day2.Pattern;

import java.util.regex.Pattern;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForMatches {
    public static void main(String args[]) {
        System.out.println( Pattern.matches("\\d+","12345") );   //true
        System.out.println( Pattern.matches("\\d+","234aa") );  //false,需要整個字元串都比對到,顯然aa不滿足條件
        System.out.println( Pattern.matches("\\d+","22aa34") ); //false,需要整個字元串都比對到,同樣中間的aa不滿足條件
    }
}
           
3.public Matcher matcher(CharSequence input)

public Matcher matcher(CharSequence input)

用于傳回一個Matcher執行個體對象,由于Matcher類的構造方法是預設通路權限的(即同包内才能通路),外部不能随意建立,隻能通過

public Matcher matcher(CharSequence input)

方法得到該類的執行個體。

Pattern類隻能做一些簡單的比對操作,要想得到更強更便捷的正則比對操作,那就需要将Pattern與Matcher一起合作。Matcher類提供了對正規表達式的分組支援,以及對正規表達式的多次比對支援。例如:

package month12.day2.Pattern;

import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForMatcher {
    public static void main(String args[]) {
        Pattern p = Pattern.compile("\\d+");
        Matcher matcher = p.matcher("12345aaa");
        System.out.println( matcher.pattern() );  //傳回p,也就是傳回該Matcher對象是由哪個Pattern對象的建立的
    }
}
           

Matcher類

1.構造方法

一個Matcher對象是一個狀态機器(比對器),它依據Pattern對象作為比對模式對字元串展開比對檢查。首先一個Pattern執行個體訂制了一個所用文法與perl(即Perl語言,内部內建了正規表達式則功能)的類似的正規表達式經編譯後的模式,然後一個Matcher執行個體在這個給定的Pattern執行個體的模式控制下進行字元串的比對工作。同樣的,Matcher執行個體對象外部不能随意建立,因為其構造方法是預設通路權限的(default),隻能通過Pattern的matcher()方法得到一個Matcher執行個體對象。(參考Pattern的第3點)

2.成員方法

1.public Pattern pattern()

public Pattern pattern()

用于傳回建立此比對器的模式。同樣的,例子可參考Pattern的第3點。

2.public Matcher usePattern(Pattern newPattern)

public Matcher usePattern(Pattern newPattern)

用于更改此

Matcher

用于查找比對項的

Pattern

。此方法可導緻比對器丢失有關最後發生比對的組的資訊。維持了輸入中比對器的位置并且不影響其最後添加的位置。例如:

package month12.day2.Pattern;

import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForMatcher {
    public static void main(String args[]) {
        Pattern p = Pattern.compile("\\d+");
        Pattern newP = Pattern.compile("\\s+");
        Matcher matcher = p.matcher("12345aaa");
        System.out.println( matcher.pattern() );  //傳回p,也就是傳回該Matcher對象是由哪個Pattern對象的建立
        matcher.usePattern(newP);
        System.out.println( matcher.pattern() );  //傳回newP,目前模式比對Pattern對象已經更新
    }
}
           

注意:如果

newPattern

null

,将抛出

IllegalArgumentException

異常。

3.public boolean find() & public boolean matches() & public boolean lookingAt()

(1).

public boolean find()

對字元串進行比對,比對到的字元串可以在任何位置。如果該方法的前一次調用成功了并且從那時開始比對器沒有被重置,則從以前比對操作沒有比對的第一個字元開始。即下一次比對從以前比對操作沒有比對的第一個字元開始。例如:

package month12.day2.matcher;
import java.util.regex.*;
/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForFind {
    public static void main(String args[]) {
        Pattern p=Pattern.compile("\\d+");
        Matcher m=p.matcher("22bb23");     //傳回true
        System.out.println( m.find() );

        Matcher m2=p.matcher("aa2223");    //傳回true
        System.out.println( m2.find() );

        Matcher m3=p.matcher("aa2223bb");   //傳回true
        System.out.println( m3.find() );

        Matcher m4=p.matcher("aabb");        //傳回false
        System.out.println( m4.find() );
    }
}
           

(2).

public boolean matches()

對整個字元串進行比對,隻有整個字元串都比對了才傳回true。例如:

package month12.day2.matcher;

import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForMatches {
    public static void main(String args[]) {
        Pattern p=Pattern.compile("\\d+");
        Matcher m=p.matcher("2223");     //傳回true
        System.out.println( m.matches() );

        Matcher m2=p.matcher("aa2223");    //傳回false,因為前面的aa不能被\d+比對,導緻整個字元串比對不成功
        System.out.println( m2.matches() );

        Matcher m3=p.matcher("aa2223bb");   //傳回false
        System.out.println( m3.matches() );

        Matcher m4=p.matcher("aabb");        //傳回false
        System.out.println( m4.matches() );
    }
}
           

(3).lookingAt()對前面的字元串進行比對,隻有比對到的字元串在最前面才傳回true例如:

package month12.day2.matcher;

import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForLookingAt {
    public static void main(String args[]) {
        Pattern p=Pattern.compile("\\d+");
        Matcher m=p.matcher("22bb23");     //傳回true
        System.out.println( m.lookingAt() );

        Matcher m2=p.matcher("22aa2223");    //傳回true
        System.out.println( m2.lookingAt() );

        Matcher m3=p.matcher("aa2223bb");   //傳回false,由于前面的aa不能比對\d+
        System.out.println( m3.lookingAt() );

        Matcher m4=p.matcher("aabb22");        //傳回false
        System.out.println( m4.lookingAt() );
    }
}
           
4.public int start() & public int end() & public String group()

當使用matches(),lookingAt(),find()執行比對操作後,就可以利用以上三個方法得到更詳細的資訊。

start()傳回比對到的子字元串在字元串中的索引位置。

end()傳回比對到的子字元串的最後一個字元在字元串中的索引位置。實際上是比對到的字元串的組的後一個字元串的索引位置。

group()傳回比對到的子字元串。

例如:

package month12.day2.matcher.compare2;

import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForStartAndEnd {
    public static void main(String args[]) {
        Pattern p=Pattern.compile("\\d+");
        Matcher m=p.matcher("aaa2223bb");
        System.out.println( m.find() + " start at: " + m.start() + " end at: "  + m.end() + " group: " + m.group());

        Matcher m2=p.matcher("2223bb");
        System.out.println( m2.lookingAt() + " start at: " + m2.start() + " end at: "  + m2.end() + " group: " + m2.group());

        Matcher m3=p.matcher("223344");
        System.out.println( m3.matches() + " start at: " + m3.start() + " end at: "  + m3.end() + " group: " + m3.group());
    }
}
           

程式運作結果:

Java正規表達式學習(二)

重載方法:start(),end(),group()均有一個重載方法它們是start(int i),end(int i),group(int i)專用于分組操作。Matcher類還有一個groupCount()用于傳回Pattern模式比對有多少組(()分組)。例如:

package month12.day2.matcher.compare2;

import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForGroup {
    public static void main(String args[]) {
        Pattern p=Pattern.compile("([a-z]+)(\\d+)");
        Matcher m=p.matcher("aaa2223bb");
        System.out.println(  m.find() );         //傳回true,比對aaa2223
        System.out.println(  m.groupCount() );   //傳回2,因為有2組
        System.out.println(  m.start() );   //傳回0 傳回第一組比對到的子字元串在字元串中的索引号
        System.out.println(  m.start() );   //傳回3
        System.out.println(  m.end() );   //傳回3 傳回第一組比對到的子字元串的最後一個字元在字元串中的索引位置.
        System.out.println(  m.end() );   //傳回7
        System.out.println(  m.group() );  //傳回aaa,傳回第一組比對到的子字元串
        System.out.println(  m.group() );   //傳回2223,傳回第二組比對到的子字元串

        System.out.println( m.group() );   //傳回aaa2223
                                            //group0永遠都表示整個與Pattern模式比對的字元串,是以不參與分組計算
    }
}
           

特别注意:隻有當比對操作成功,才可以使用start(),end(),group()三個方法,否則會抛出java.lang.IllegalStateException,也就是當matches(),lookingAt(),find()其中任意一個方法傳回true時,才可以使用。

補充:關于groupCount()的一點補充:

package month12.day2.matcher;
import java.util.regex.*;
/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForGroupCount {
    public static void main(String args[]) {
        Pattern p1 = Pattern.compile("\\d{3,5}");
        Matcher m1 = p1.matcher("aaa2223bb");
        System.out.println( m1.groupCount() );        //0

        Pattern p2 = Pattern.compile("([a-z]+)(\\d+)");
        Matcher m2 = p2.matcher("aaa2223bb");
        System.out.println( m2.groupCount() );        //2

        Pattern p3 = Pattern.compile("(([a-z]+)(\\d+))");
        Matcher m3 = p3.matcher("aaa2223bb");
        System.out.println( m3.groupCount() );        //3
    }
}
           

一個簡單的正規表達式找出字元串中的數字的例子:

package month12.day2.matcher;
import java.util.regex.*;
/**
 * Created by Administrator on 2016/12/2.
 */
public class GetNumberSample {
    public static void main(String args[]) {
        Pattern p=Pattern.compile("\\d+");
        Matcher m=p.matcher("我的QQ是:123456 我的電話是:0984290765 我的郵箱是:[email protected]");
        while(m.find()) {
            System.out.println(m.group());
            System.out.print("start:"+m.start());
            System.out.println(" end:"+m.end());
        }
    }
}
           

程式運作結果:

Java正規表達式學習(二)

每次執行比對操作成功後start(),end(),group()三個方法的值都會改變,改變成比對到的子字元串的資訊,以及它們的重載方法,也會改變成相應的資訊。

5.public Matcher reset()

public Matcher reset()

的作用是重置比對器,重置比對器将放棄其所有顯式狀态資訊并将其添加位置設定為零。比對器的區域被設定為預設區域,預設區域就是其整個字元序列。例如:

package month12.day2.matcher;

import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForReset {
    public static void main(String args[]) {
        Pattern p = Pattern.compile("\\d{3,5}");
        String s = "123-34345-234-00";
        Matcher m = p.matcher(s);
        System.out.println(m.find()+" start at:"+m.start()+" end at:"+m.end());
        System.out.println(m.find()+" start at:"+m.start()+" end at:"+m.end());
        m.reset();
        System.out.println(m.find()+" start at:"+m.start()+" end at:"+m.end());
        System.out.println(m.find()+" start at:"+m.start()+" end at:"+m.end());
    }
}
           

程式運作結果:

Java正規表達式學習(二)

上述結果說明:執行個體對象m reset()之後,以前比對過的資訊全部重置,重新開始從頭比對。

**重載方法

public Matcher reset(CharSequence input)

重設該Matcher對象并且指定一個新的目标字元串。**

6.public String replaceFirst(String replacement) & public String replaceAll(String replacement)

String replaceAll(String replacement)

将目标字元串裡與既有模式相比對的子串全部替換為指定的字元串

String replaceFirst(String replacement)

将目标字元串裡第一個與既有模式相比對的子串替換為指定的字元串。例如:

package month12.day2.matcher;
import java.util.regex.*;

/**
 * Created by Administrator on 2016/12/2.
 */
public class TestForReplace {
    public static void main(String args[]) {
        Pattern p = Pattern.compile("\\d{3,5}");
        String s = "123-34345-234-00";
        Matcher m = p.matcher(s);
        System.out.println( m.replaceFirst("hello") );      //hello-34345-234-00
        System.out.println( m.replaceAll("hello") );        //hello-hello-hello-00
    }
}
           
7.public Matcher appendReplacement(StringBuffer sb, String replacement) & public StringBuffer appendTail(StringBuffer sb)

appendReplacement(StringBuffer sb, String replacement)

将目前比對子串替換為指定字元串,并且将替換後的子串以及其之前到上次比對子串之後的字元串段添加到一個StringBuffer對象裡,而

appendTail(StringBuffer sb)

方法則将最後一次比對工作後剩餘的字元串添加到一個StringBuffer對象裡。例如(這個在學習(一)中的小程式):

import java.util.regex.*;
public class RegexReplacement {
    public static void main(String[] args)
            throws Exception {
        Pattern pattern = Pattern.compile("cat");
        Matcher matcher = pattern.matcher(
                "one cat, two cats in the yard");
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "big $0");
        }
        matcher.appendTail(sb);
        System.out.println(sb.toString());
    }
}
           

程式運作結果:

Java正規表達式學習(二)

對以上程式的解釋:

字元串one cat, two cats in the yard,正規表達式模式為”cat”,第一次比對後,cat子字元串與模式比對,調用appendReplacement(sb,”big cat”),那麼這時StringBuffer sb的内容為one big cat,也就是cat被替換為big cat并且與比對子串前的内容加到sb裡,而第二次比對後調用appendReplacement(sb,”big cat”),那麼sb的内容就變為one big cat,two big cats,如果最後再調用一次appendTail(sb),那麼sb最終的内容将是one big cat, two big cats in the yard。

也可以在while循環中,對group(0)進行驗證,while循環的代碼可以改成如下:

while (matcher.find()) {
    System.out.println(matcher.group());
    matcher.appendReplacement(sb, "big $0");
}
           

程式運作結果:

Java正規表達式學習(二)

未完待續見Java正規表達式學習(三)