1. 程式人生 > >Java正則表示式API詳解

Java正則表示式API詳解

1. Pattern類

public class PatternExample {
    /**
     * public static String quote(String s)
     * 返回指定字串的字面值模式, 也就是說字串序列中的元字元和轉義序列將不具有特殊含義.
     * 會使用\Q \E包裹, \Q \E中間的字元是字面意思, 不具有特殊含義.
     * 
     * public static Pattern compile(String regex, int flag)
     * 編譯給定正則表示式
     * flag: 匹配標誌, 常用的如下解釋
     * CASE_INSENSITIVE: 匹配時大小寫不敏感.
     * MULTILINE: 啟用多行模式, ^ $匹配行的開頭和結尾, 而不是整個輸入序列的的開頭和結尾.
     * UNIX_LINES: 啟用UNIX換行符, 在多行模式中使用^ $時只有\n被識別成終止符.
     * DOTALL: 在此模式中元字元.可以匹配任意字元, 包括換行符.
     * LITERAL: 啟用模式的字面值意思, 模式中的元字元、轉義字元不再具有特殊含義.
     * 
     * public static boolean matches(String regex, String s)
     * 判斷整個輸入序列是否與給定的模式匹配.
     * 底層呼叫Matcher例項的matchers方法
     */
    @Test
    public void quote() {
        String regex1 = Pattern.quote(".java");
        Assert.assertEquals("\\Q.java\\E", regex1);
        Matcher matcher = Pattern.compile(regex1).matcher("Effect.java");
        Assert.assertTrue(matcher.find());

        String regex2 = Pattern.quote("\\.java");
        Assert.assertEquals("\\Q\\.java\\E", regex2);
        Assert.assertTrue(Pattern.compile(regex2).matcher("Effect\\.java").find());
        Assert.assertFalse(Pattern.compile(regex2).matcher("Effect.java").find());
    }

    @Test
    public void matchesVsFind() {
        String s = "satat";
        String regex = "at";
        Assert.assertFalse(Pattern.matches(regex, s));
        Assert.assertTrue(Pattern.compile(regex).matcher(s).find());
        Assert.assertFalse(Pattern.compile("^at").matcher(s).find());
    }

2. Matcher

public class MatcherExample {

    /**
     * 匹配操作
     * public boolean lookingAt()
     * 嘗試將整個輸入序列的開始處與模式匹配, 對於輸入序列的結尾處不做要求
     * 也就是說從左(必須是序列的開頭)到右有一處與模式匹配, 便返回true.
     * 
     * public boolean matches()
     * 嘗試將整個輸入序列與模式匹配, 只有從頭到尾完全與模式匹配才返回true.
     * 
     * public boolean find()
     * 只要整個輸入序列或者子序列有一個與模式匹配, 便返回true.
     * find方法可用來尋找輸入序列中所有與模式匹配的子序列.
     * 
     * 上述三個方法返回true時, 可以使用start, end, group方法獲取詳細資訊
     * 返回false時或者沒有呼叫過匹配方法, 呼叫start, end, group會丟擲異常"No match available"
     * 
     * public int start()
     * 返回匹配序列在輸入序列中的初始索引.
     * public int start(int group)
     * 返回給定組捕獲的匹配序列在輸入序列中的初始索引, 如果給定模式匹配成功,
     * 但是模式中的指定組沒有匹配返回-1.
     * 如果模式中沒有指定的組將丟擲異常IndexOutOfBoundsException: No group ${group}
     * 
     * public int end()
     * 返回匹配序列中最後一個字元在輸入序列中的索引+1.
     * public int end(int group)
     * 返回給定組捕獲的匹配序列中最後一個字元在輸入序列中索引+1,
     * 如果給定模式匹配成功, 但是模式中的指定組沒有匹配返回-1.
     * 如果模式中沒有指定的組將丟擲異常IndexOutOfBoundsException: No group ${group}
     * 
     * public String group()
     * 返回匹配序列
     * public String group(int group)
     * 返回給定組捕獲的匹配序列.
     * 如果給定模式匹配成功, 但是模式中的指定組沒有匹配返回null.
     * 如果模式中沒有指定的組將丟擲異常IndexOutOfBoundsException: No group ${group}
     */
    @Test
    public void match() {
        String goal = "at sat cat mat";
        String regex = ".?at(a)?";
        Matcher matcher = Pattern.compile(regex).matcher(goal);
        // 從開始處匹配
        Assert.assertTrue(matcher.lookingAt());
        Assert.assertEquals(0, matcher.start());
        Assert.assertEquals(2, matcher.end());
        Assert.assertEquals("at", goal.substring(matcher.start(), matcher.end()));
        Assert.assertEquals("at", matcher.group());
        // 組1(a)沒有匹配到, 返回-1
        Assert.assertEquals(-1, matcher.start(1));
        Assert.assertEquals(-1, matcher.end(1));
        Assert.assertNull(matcher.group(1));
    }

    /**
     * 修改或讀取當前模式匹配輸入序列的範圍(區域), 預設是全部區域.
     * 查詢時包頭不包尾(subString()方法一樣的含義)
     */
    @Test
    public void region() {
        String goal = "33abcd55";
        String regex = "abcd";
        Matcher matcher = Pattern.compile(regex).matcher(goal);
        // 查詢開始索引
        Assert.assertEquals(0, matcher.regionStart());
        // 查詢結尾索引
        Assert.assertEquals(goal.length(), matcher.regionEnd());
        Assert.assertFalse(matcher.matches());
        matcher.reset();
        // 調整區域, 相當於擷取${goal}的abcd來匹配.
        matcher.region(2, 6);
        Assert.assertTrue(matcher.matches());
        Assert.assertEquals(2, matcher.regionStart());
        Assert.assertEquals(6, matcher.regionEnd());
    }

    @Test
    public void group() {
        String goal = "pig dog cat snake horse dog cat tiger monkey";
        String regex = "(dog)\\s*(cat)\\s*?";
        Matcher matcher = Pattern.compile(regex).matcher(goal);
        // 查詢所有與模式匹配的串
        while (matcher.find()) {
            // result: dog cat
            System.out.println(matcher.group());
            // result: [dog, cat]
            for (int i = 1; i <= matcher.groupCount(); i++) {
                if (i == 1) {
                    System.out.print("[" + matcher.group(i));
                } else if (i == matcher.groupCount()) {
                    System.out.println(", " + matcher.group(i) + "]");
                } else {
                    System.out.print(", " + matcher.group(i));
                }
            }
            System.out.println("-----------------");
        }
    }

    /**
     * public Matcher appendReplacement(StringBuffer sb, String replacement)
     * 將目標字串與模式匹配的部分替換成replacement, 將結果放到sb中
     * 此方法只會替換一處匹配的地方, 並且目標字串的後續部分不會存放到sb中
     * 其中replacement可以使用反向引用來獲取捕獲組的內容
     * 反向引用規則(僅適用於Java):
     * 1. 使用捕獲組編號,  $n  其中0 <= n <=groupCount()
     * 2. 使用捕獲組名稱,  ${name}  name以非數字開頭
     * replacement只會涉及到兩個字元的轉義: 1. $  ->  \\$   2. \   ->   \\
     * 例子:
     * String gaol = "I like music", regex = "like, replacement = "love";
     * 那麼sb = I love
     * 
     * StringBuffer appendTail(String sb)
     * 與appendReplacement搭配工作, 目標字串剩下的內容新增到sb中
     * 接著上述例子呼叫appendTail方法, 那麼sb = I love music
     * 
     * 基於以上兩個方法便能實現replaceFirst, replaceAll兩個方法
     */
    @Test
    public void replaceFist() {
        String goal = "I like music";
        String regex = "like";
        String relpacement = "love";
        Matcher matcher = Pattern.compile(regex).matcher(goal);
        StringBuffer sb = new StringBuffer();
        if (matcher.find()) {
            matcher.appendReplacement(sb, relpacement);
            Assert.assertEquals("I love", sb.toString());
            matcher.appendTail(sb);
            Assert.assertEquals("I love music", sb.toString());
        }
    }

    /**
     * 去掉dog 和 cat
     */
    @Test
    public void replaceAll() {
        String goal = "pig dog snake cat horse dog cat tiger monkey";
        String regex = "(dog\\s?)|(cat\\s?)";
        Matcher matcher = Pattern.compile(regex).matcher(goal);
        StringBuffer sb = new StringBuffer();
        boolean flag = false;
        while (matcher.find()) {
            matcher.appendReplacement(sb, "");
            flag = true;
        }
        if(flag) {
            sb = matcher.appendTail(sb);
            Assert.assertEquals("pig snake horse tiger monkey", sb.toString());
        }
    }

    /**
     * 去重
     */
    @Test
    public void removeDuplicate() {
        String goal = "aabbcddeefgg";
        String regex = "(\\w)\\1+";
        Matcher matcher = Pattern.compile(regex).matcher(goal);
        String result = matcher.replaceAll("$1");
        Assert.assertEquals("abcdefg", result);
    }
}