NO IMAGE

平時在對字串進行操作的時候進行用到正規表示式,影響最深刻的是2011開發新華網微博的時候,對微博內容做了複雜的正規表示式校驗。接下來介紹一下Java中的正規表示式的使用。以下內容基於JDK1.7進行講解。

Java中預設的正規表示式是貪婪匹配的。
Javascript中預設的正規表示式也是貪婪匹配的。

這裡留下一個問題:什麼是貪婪匹配,後續做詳細說明。

在Java中,java.util.regex包定義了正規表示式使用到的相關類,其中最主要的兩個類為:Pattern、Matcher。

  • Pattern 編譯正規表示式後建立一個匹配模式。
  • Matcher 使用Pattern例項提供的正規表示式對目標字串進行匹配。

Pattern類

  • private Pattern(String p, int f) 私有的構造方法。
  • public static Pattern compile(String regex) 通過靜態方法compile建立Pattern物件,檢視原始碼發現compile直接呼叫了Pattern建構函式。
    public static Pattern compile(String regex) {
return new Pattern(regex, 0);
}
  • public static Pattern compile(String regex, int flags) 通過靜態方法compile建立Pattern物件,檢視原始碼發現compile直接呼叫了Pattern建構函式,該方法允許設定多個Match Flag,如Pattern.CASE_INSENSITIVE|Pattern.UNIX_LINES,關於Match Flag後續做詳細說明。
    public static Pattern compile(String regex, int flags) {
return new Pattern(regex, flags);
}
  • public String pattern() 返回字串型別的正規表示式,也就是compile函式的regex引數值。
  • public Matcher matcher(CharSequence input) 為目標字串input建立一個Matcher物件。
  • public int flags() 返回當前Pattern物件的Match Flag值,如果設定的值為Pattern.CASE_INSENSITIVE|Pattern.UNIX_LINES,則返回累加和。Pattern.CASE_INSENSITIVE的值為0x02Pattern.UNIX_LINES的值為0x01,則flags()返回值為3。
  • public static boolean matches(String regex, CharSequence input) 通過指定的正規表示式regex對input進行正則匹配,該方法適用於只進行一次匹配的任務,因為該方法不生成Matcher例項。
  • public String[] split(CharSequence input) 通過正規表示式對input進行分割。
  • public String[] split(CharSequence input, int limit) 通過正規表示式對input進行分割,limit引數指明分割的段數。
  • public static String quote(String s) 將字串s轉換為正則字面量,正規表示式“.”表示匹配除“\n”之外的任何字元零次或多次,使用quote進行轉換後“.”只能匹配“.*”,沒有當初的正則的含義了。在使用quote()方法之後,原有的字串s變成了\Qs\E的樣式,\Q 代表字面內容的開始,\E 代表字面內容的結束。

Matcher類

  • Matcher(Pattern parent, CharSequence text) 構造方法。
  • public Pattern pattern() 返回建立Matcher物件的Pattern物件。
  • public MatchResult toMatchResult() 將匹配結果以MatchResult的形式返回
  • public Matcher usePattern(Pattern newPattern) 修改Matcher物件的Pattern,用以進行新的模式匹配。
  • public Matcher reset() 重置匹配器的狀態。
  • public Matcher reset(CharSequence input) 重置匹配器的狀態,重置目標字串的值為input。
  • public int start() 返回當前匹配到的字串在原目標字串中的起始索引位置
  • public int start(int group) 返回當前匹配到的字串中group組在目標字串的起始索引位置
  • public int end() 返回當前匹配的字串的最後一個字元在原目標字串中的offset(偏移量),這個需要大家注意一下。
  • public int end(int group) 返回當前匹配的字串中group組的最後一個字元在原目標字串中的offset(偏移量),這個需要大家注意一下。
  • public String group() 返回匹配到的字串,結合find函式使用。
  • public String group(int group) 返回匹配到的字串中的group組的字串。
  • public String group(String name) 返回被named-capturing組捕獲的字串,關於named-capturing group(命名捕獲組)是JDK1.7新增的功能,可以將正規表示式中的組進行命名。

(?X) 定義一個名為groupName的組。
\k 用於向後引用(back reference)名為groupName的組。
${groupName} 用於,在替換函式中,後向引用名為groupName的組。
group(groupName) 用於獲得對應的帶捕獲的名為groupName的組的值。

  • public int groupCount() 返回當前Matcher物件捕獲的組的個數。
  • public boolean matches() 將整個目標字串與正規表示式進行匹配,只有完全匹配才能返回true,否則false。
  • public boolean find() 對目標字串進行正則匹配,通過while可以多次執行find方法,獲取多次的匹配結果,程式碼編寫方式類似於iterator.next()。
  • public boolean find(int start) 在制定的索引位置對目標字串進行正則匹配。
  • public boolean lookingAt() 目標字串的起始字串與正規表示式匹配返回true,否則返回false。
  • public static String quoteReplacement(String s) 返回字串s字面意義的替代字串。
  • public Matcher appendReplacement(StringBuffer sb, String replacement) 向sb中追加replacement字串,replacement字串中可以包含匹配器中的分組引數,如1,1,2。
  • public StringBuffer appendTail(StringBuffer sb) 將Matcher匹配後的尾部字串追加至sb中,示例程式碼如下:
    public static void main(String[] args) {
Pattern p = Pattern.compile("cat");
Matcher m = p.matcher("one cat two cats in the yard");
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "dog");
}
m.appendTail(sb);
System.out.println(sb.toString());
}
執行結果:one dog two dogs in the yard
  • public String replaceAll(String replacement) 將目標字串中所有滿足正則匹配的字串替換為replacement。
  • public String replaceFirst(String replacement) 將目標字串中第一個滿足正則匹配的字串替換為replacement。
  • public Matcher region(int start, int end) 設定目標字串的匹配範圍。
  • public int regionStart() 返回匹配器區域的起始點索引位置。
  • public int regionEnd() 返回匹配器區域的結束點索引位置。
  • public boolean hasTransparentBounds() TransparentBounds標誌位:查詢TransparentBounds標誌位true|false,此標誌位預設為false。如果匹配範圍不是整個目標字串,而是一部分,那麼如果此標誌位設為true的話,則允許順序環視、逆序環視以及單詞分界符超越匹配範圍邊界的設定,匹配目標字串的其他部分,也就是可以稍微有越界行為。可以通過useTransparentBounds()進行修改設定。
  • public Matcher useTransparentBounds(boolean b) 設定TransparentBounds標誌位的值true|false。
    public static void main(String[] args) {
String regex = "\\bcar\\b";
String text = "Madagascar is best seen by car or bike.";
Matcher m = Pattern.compile(regex).matcher(text);
m.region(7, text.length());
m.useTransparentBounds(false);
m.find();
System.out.println("Matches starting at character "   m.start());
m.reset();
m.useTransparentBounds(true);
m.find();
System.out.println("Matches starting at character "   m.start());
}
執行結果:
Matches starting at character 7
Matches starting at character 27
\b 匹配一個字邊界,即字與空格間的位置。例如,“er/b”匹配“never”中的“er”,但不匹配“verb”中的“er”。
TransparentBounds = false,region區域從index=7開始,Madagascar也就是從car開始,匹配器無法感知region區域外的字元,因此第一個car被匹配。
TransparentBounds = true,region區域從index=7開始,Madagascar也就是從car開始,匹配器可以感知region區域外的字元,因此第一個car不被匹配。   
  • public boolean hasAnchoringBounds() AnchoringBounds標誌位:查詢AnchoringBounds標誌位的值,此標誌位預設為true。在應用正規表示式的時候,我們可以指定目標字串的檢索範圍,也就是說在目標字串的子字串中應用正規表示式。但此時會有一個問題,那就是 ^ 和 $ 應該匹配整個字串的開頭和結尾呢? 還是檢索範圍的起始和結束位置呢?Java 為我們提供了足夠的靈活性,我們可以通過下面的方法來檢視和設定,預設值是匹配檢索範圍的起始和結束位置。
  • public Matcher useAnchoringBounds(boolean b) 設定AnchoringBounds標誌位的值true|false。
  • public boolean hitEnd()
  • public boolean requireEnd()
  • boolean search(int from)
  • boolean match(int from, int anchor)
  • int getTextLength() 返回目標字串的長度。
  • CharSequence getSubSequence(int beginIndex, int endIndex) 獲取目標字串的子字串。
  • char charAt(int i) 返回目標字串中索引為i的字元