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);
}
}