Pattern 物件

July 2, 2022

剖析、驗證規則表示式往往是最耗時間的階段,在頻繁使用某規則表示式的場合,若能重複使用剖析、驗證過後的規則表示式,對效率會有幫助。

建立Pattern

java.util.regex.Pattern 實例是規則表示式代表物件,Pattern 的建構式被標示為 private,無法用 new 建構 Pattern 實例,必須透過 Pattern 的靜態方法 compile,在剖析、驗證過規則表示式無誤後,compile 會傳回 Pattern 實例,之後就可以重用這個實例。例如:

var pattern = Pattern.compile(".*foo");

Pattern.compile 方法的另一版本,可以指定旗標(Flag),例如想不分大小寫比對 dog 文字,可以如下:

var pattern = Pattern.compile("dog", Pattern.CASE_INSENSITIVE);

指定旗標 Pattern.LITERAL 的話,字串撰寫規則表示式時,就不用迴避詮譯字元(不過 \ 還是得迴避,以免與字串表示法衝突):

jshell> import java.util.regex.Pattern;

jshell> var pattern = Pattern.compile("+", Pattern.LITERAL);
pattern ==> +

jshell> pattern.split("Justin+Monica")
$1 ==> String[2] { "Justin", "Monica" }

函數式概念 API

Pattern 有個 splitAsStream 靜態方法,它傳回的是 Stream<String>,適用於需要管線化、惰性操作的場合:

jshell> var regex = Pattern.compile("\\+");
regex ==> \+

jshell> var tokens = regex.splitAsStream("Justin+Monica+Irene");
tokens ==> java.util.stream.ReferencePipeline$Head@5a1c0542

jshell> tokens.filter(token -> token.indexOf('i') != -1).map(String::toUpperCase).forEach(out::println);
JUSTIN
MONICA

Pattern 實例可以藉由 asPredicate 轉為 Predicate 物件,在需要 Predicate 作為引數的場合時可以使用:

jshell> var regex = Pattern.compile("\\+");
regex ==> \+

jshell> var tokens = regex.splitAsStream("Justin+Monica+irene");
tokens ==> java.util.stream.ReferencePipeline$Head@2833cc44

jshell> tokens.filter(Pattern.compile("\\p{Upper}+").asPredicate()).forEach(System.out::println);
Justin
Monica

嵌入旗標表示法

也可以在規則表示式使用嵌入旗標表示法(Embedded Flag Expression)。例如 Pattern.CASE_INSENSITIVE 等效的嵌入旗標表示法為 (?i),以下片段效果等同上例:

var pattern = Pattern.compile("(?i)dog");

若想對特定分組嵌入旗標,可以使用 (?i:dog) 這樣的語法;並非全部的常數旗標都有對應的嵌入式表示法,底下列出有對應的旗標:

  • Pattern.CASE_INSENSITIVE(?i)
  • Pattern.COMMENTS(?x)
  • Pattern.MULTILINE(?m)
  • Pattern.DOTALL(?s)
  • Pattern.UNIX_LINES(?d)
  • Pattern.UNICODE_CASE(?u)
  • Pattern.UNICODE_CHARACTER_CLASS(?U)

Pattern.COMMENTS 允許在規則表示式以 # 嵌入註解;Pattern.MULTILINE 啟用多行文字模式(影響了 ^$ 的行為,換行字元後、前會被視為行首、行尾);預設情況下.不匹配換行字元,可設置 Pattern.DOTALL 來匹配換行字元;Pattern.UNIX_LINES 啟用後,只有 \n 才被視為換行字元,作為 .^$判斷依據。

Pattern.UNICODE_CASEPattern.UNICODE_CHARACTER_CLASS 與規則表示式 Unicode 支援有關,稍後再來說明。

規則表示式本身可讀性差、除錯不易,若因規則表示式有誤而導致 compile 呼叫失敗,會拋出 java.util.regex.PatternSyntaxException,可以使用 getDescription 取得錯誤說明、getIndex 取得錯誤索引、getPattern 取得錯誤的規則表示式,getMessage 會以多行顯示錯誤的索引、描述等綜合訊息。

分享到 LinkedIn 分享到 Facebook 分享到 Twitter