String 與 Regex


Java 沒有為規則表示式制定專用的實字(Literal)撰寫方式,也沒有像 Python 的原始字串特性,因此在 Java 中撰寫規則表示式,實際上是蠻麻煩的。

若有個 Java 字串是 "Justin+Monica+Irene", 想使用 split 方法依 + 切割,要使用的規則表示式是 \+,要將 \+ 放至 "" 之間時,按照 Java 字串的規定,必須轉義 \+\,所以必須撰寫為 "\\+"

jshell> "Justin+Monica+Irene".split("\\+");
$1 ==> String[3] { "Justin", "Monica", "Irene" }

類似地,如果有個 Java 字串是 "Justin||Monica||Irene",想使用 split 方法依 || 切割,要使用的規則表示式是 \|\|,要將 \|\| 放至 "" 之間時,按照 Java 字串規定必須忽略 \|\,就必須撰寫為 "\\|\\|"。例如:

jshell> "Justin||Monica||Irene".split("\\|\\|");
$2 ==> String[3] { "Justin", "Monica", "Irene" }

如果有個字串是 "Justin\\Monica\\Irene",也就是原始文字是 Justin\Monica\Irene 以 Java 字串表示,若想使用 split 方法依 \ 切割,要使用的規則表示式是 \\,那就得如下撰寫:

jshell> "Justin\\Monica\\Irene".split("\\\\");
$3 ==> String[3] { "Justin", "Monica", "Irene" }

這麼撰寫當然非常的麻煩,java.util.regex.Pattern 提供了 quote 靜態方法,可以幫你對規則表示式的詮譯字元進行轉義:

jshell> import static java.util.regex.Pattern.quote;

jshell> "Justin+Monica+Irene".split(quote("+"));
$4 ==> String[3] { "Justin", "Monica", "Irene" }

jshell> "Justin||Monica||Irene".split(quote("||"));
$5 ==> String[3] { "Justin", "Monica", "Irene" }

jshell> "Justin\\Monica\\Irene".split(quote("\\"));
$6 ==> String[3] { "Justin", "Monica", "Irene" }

quote 方法實際上會在指定的字串前後加上 \Q\E,這個表示法在 Java 中用來表示 \Q\E 之間的全部字元,都不當成詮譯字元。

jshell> Pattern.quote(".");
$7 ==> "\\Q.\\E"

如果要將字串編譯為 Pattern 物件,可以指定旗標 Pattern.LITERAL,這樣會將全部的詮譯字元當成一般字元來比對。

相對地,如果想要取代字串,打算使用 $ 之類的符號,也必須進行轉義:

jshell> "java.exe".replaceFirst(quote("."), "\\$");
$8 ==> "java$exe"

因為 $ 用來作為分組參考的前置字元,如果不轉義的話會發生例外:

jshell> "java.exe".replaceFirst(quote("."), "$");
|  Exception java.lang.IllegalArgumentException: Illegal group reference: group index is missing
|        at Matcher.appendExpandedReplacement (Matcher.java:1030)
|        at Matcher.appendReplacement (Matcher.java:998)
|        at Matcher.replaceFirst (Matcher.java:1408)
|        at String.replaceFirst (String.java:2081)
|

對於這類情況,可以使用 java.util.regex.Matcher 提供的 quoteReplacement 靜態方法:

jshell> import static java.util.regex.Matcher.quoteReplacement;

jshell> "java.exe".replaceFirst(quote("."), quoteReplacement("$"));
$9 ==> "java$exe

不過,遇到 \d\s 等預定義字元類,也只能乖乖轉義了,所幸,現代 IDE 將文字貼到 "" 裏頭時,會自動為 \ 加上轉義。例如:

String 與 Regex

這些方式搭配一下,在 Java 中撰寫規則表示式時,應該就可以省不少功夫吧!…XD

String 上可以使用規則表示式的方法,在方才已經看過 splitreplaceFirst,另外還有 replaceAll 方法。注意到 replace 方法,是不支援規則表示式的:

String replace​(char oldChar, char newChar)

matches 方法用來測試全字串是否符合規則表示式:

jshell> "0970-168168".matches("\\d{4}-\\d{6}");
$10 ==> true

jshell> "Phone: 0970-168168".matches("\\d{4}-\\d{6}");
$11 ==> false