JavaRush /Java Blog /Random-TW /Java 中的正規表示式,第 3 部分

Java 中的正規表示式,第 3 部分

在 Random-TW 群組發布
我們向您展示 Java 正規表示式簡短指南的翻譯,該指南由 Jeff Friesen 為javaworld網站編寫。為了方便閱讀,我們將文章分成幾個部分。 Java 中的正規表示式,第 3 部分 - 1Java 中的正規表示式,第 1 部分 Java 中的正規表示式,第 2 部分

使用 Regex API 簡化常見程式設計任務

在本文的第 1 部分和第 2 部分中,我們向您介紹了正規表示式和 Regex API。您了解了該類Pattern,並瀏覽了演示正則表達式構造的範例,從使用文字字串的簡單模式匹配到使用範圍、邊界匹配器和量詞的更複雜的匹配。在本部分和後續部分中,我們將考慮第一部分中未涵蓋的問題,我們將研究類別PatternMatcher和的相應方法PatternSyntaxException。您還將學習兩個使用正規表示式來簡化常見程式設計問題的實用程式。第一個從程式碼中提取註釋以用於文件。第二個是可重複使用程式碼庫,旨在執行詞法分析 - 彙編器、編譯器和類似軟體的重要組成部分。

下載原始碼

您可以從此處取得本文中演示應用程式的所有原始程式碼(由 Jeff Friesen 為 JavaWorld 建立)。

學習正規表示式 API

PatternMatcherPatternSyntaxException是構成 Regex API 的三個類別。它們每個都提供允許您在程式碼中使用正規表示式的方法。

Pattern 類別的方法

類別的實例Pattern是編譯後的正規表示式,也稱為模式。編譯正規表示式是為了提高模式匹配操作的效能。以下靜態方法支援編譯。
  • Pattern compile(String regex)將內容編譯regex為儲存在新的Pattern. 如果成功,此方法傳回對物件的參考;PatternSyntaxException如果偵測到無效的正規表示式語法,則會拋出異常。Matcher該物件使用或返回的類別的任何物件都Pattern使用其預設設置,例如區分大小寫的搜尋。例如,程式碼片段Pattern p = Pattern.compile("(?m)^\\."); 建立一個對象Pattern,該物件儲存正規表示式的編譯表示形式,以匹配以點字元開頭的字串。

  • Pattern compile(String regex, int flags)解決與 相同的問題Pattern compile(String regex),但考慮到flags: OR 類型的位元標誌的一組位元常數。此類別聲明可以使用位元 OR(例如)組合並作為參數傳遞的Pattern常數。CANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINESCASE_INSENSITIVE | DOTALLflags

  • 除了 之外CANON_EQ, LITERAL и UNICODE_CHARACTER_CLASS,這些常數是第 1 部分中演示的嵌套標誌表達式的替代方案。如果遇到類別中定義的標誌常數以外的標誌常數,則Pattern該方法Pattern compile(String regex, int flags) 將引發異常java.lang.IllegalArgumentException。例如,Pattern p = Pattern.compile("^\\.", Pattern.MULTILINE);相當於前面的範例,常數Pattern.MULTILINE和嵌套標誌表達式(?m)執行相同的操作。
有時需要取得編譯到物件中的正規表示式的原始字串的副本Pattern及其使用的標誌。為此,您可以呼叫以下方法:
  • String pattern()返回編譯成Pattern.

  • int flags()傳回物件的 flags Pattern
接收到物件後Pattern,通常用於取得物件Matcher來進行模式匹配操作。此方法Matcher matcher(Charsequence input)建立一個對象Matcher,該對像在文字中搜尋input與對像模式的匹配項Pattern。呼叫時,它會傳回對此物件的參考Matcher。例如,該命令Matcher m = p.matcher(args[1]);傳回變數 引用的Matcher物件。 Patternp
免洗
static boolean matches(String regex, CharSequence input)類別方法Pattern可讓您節省建立物件PatternMatcher使用範本進行一次性搜尋的時間。input如果模式匹配,此方法傳回 true regex,否則傳回 false。如果正規表示式包含語法錯誤,則該方法將引發異常PatternSyntaxException。例如,System.out.println(Pattern.matches("[a-z[\\s]]*", "all lowercase letters and whitespace only"));列印true,確認該短語all lowercase letters and whitespace only僅包含空格和小寫字元。
Java 中的正規表示式,第 3 部分 - 2

分割文字

大多數開發人員至少編寫過一次程式碼來將輸入文字分解為其組成部分,例如將基於文字的員工帳戶轉換為一組欄位。這類Pattern提供了使用兩種文字分割方法更方便解決這項繁瑣任務的能力:
  • 此方法根據找到的物件模式匹配String[] split(CharSequence text, int limit)進行分割,並以數組形式傳回結果。每個陣列元素指定一個文字序列,透過模式匹配文字片段(或文字結尾)與下一個序列分隔開。數組元素的順序與它們在 中出現的順序相同。textPatterntext

    在此方法中,陣列元素的數量取決於參數limit,該參數還控制要尋找的匹配項的數量。

    • 正值搜尋不超過limit-1匹配項,且數組的長度不超過limit元素。
    • 如果值為負數,則搜尋所有可能的符合項,並且陣列的長度可以是任意的。
    • 如果該值為零,則搜尋所有可能的匹配項,數組的長度可以是任意的,並且末尾的空白行將被丟棄。

  • 該方法String[] split(CharSequence text)使用 0 作為 limit 參數呼叫前一個方法並傳回其呼叫結果。
split(CharSequence text)以下是解決將員工帳戶拆分為姓名、年齡、郵寄地址和薪資欄位的問題 的方法的結果:
Pattern p = Pattern.compile(",\\s");
String[] fields = p.split("John Doe, 47, Hillsboro Road, 32000");
for (int i = 0; i < fields.length; i++)
   System.out.println(fields[i]);
上面的程式碼描述了一個正規表示式,用於尋找緊接單個空格字元的逗號字元。以下是其執行結果:
John Doe
47
Hillsboro Road
32000

模板謂詞和 Streams API

在Java 8中,類別中Pattern出現了方法。此方法建立一個用於匹配模式的謂詞(具有布林值的函數)。此方法的使用如下面的程式碼片段所示: Predicate asPredicate()
List progLangs = Arrays.asList("apl", "basic", "c", "c++", "c#", "cobol", "java", "javascript", "perl", "python", "scala");
Pattern p = Pattern.compile("^c");
progLangs.stream().filter(p.asPredicate()).forEach(System.out::println);
此程式碼會建立一個程式語言名稱列表,然後編譯一個模式以尋找以字母 開頭的所有名稱c。上面的最後一行程式碼實作了接收以此列表為來源的串列資料流。它使用布林函數設定一個過濾器asPredicate(),當名稱以字母開頭時傳回 true c,並迭代流,將匹配的名稱列印到標準輸出。最後一行相當於以下常規循環,在第 1 部分的 RegexDemo 應用程式中很常見:
for (String progLang: progLangs)
   if (p.matcher(progLang).find())
      System.out.println(progLang);

匹配器類別方法

該類別的實例Matcher描述了一種透過解釋該類別的已編譯正規表示式對字元序列執行模式匹配操作的機制Pattern。此類別的物件Matcher支援各種類型的模式搜尋操作:
  • 此方法boolean find()在輸入文字中搜尋下一個符合項。此方法從指定文字的開頭或上一個符合項目之後的第一個字元開始掃描。只有當先前對此方法的呼叫傳回 true 且解析器未重設時,才可以使用第二個選項。無論如何,如果搜尋成功,則傳回布林值 true。此方法的範例可在RegexDemo第 1 部分中找到。

  • 此方法boolean find(int start)重置匹配器並在文字中搜尋下一個匹配項。從參數指定的位置開始查看start。如果搜尋成功,則傳回布林值true。例如,m.find(1);從位置開始掃描文字1(忽略位置 0)。如果參數start包含負值或大於匹配器文字長度的值,則該方法將引發異常java.lang.IndexOutOfBoundsException

  • 該方法boolean matches()嘗試將所有內容與模式相符。如果所有文字都與該模式匹配,它將傳回一個布林值 true。例如,程式碼Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.matches());輸出是false因為該字元!不是單字字元。

  • 該方法boolean lookingAt()嘗試將給定文字與模式進行匹配。如果文字的任何部分與模式匹配,則此方法傳回 true。與方法不同matches();,所有文字不必與模式相符。例如,Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.lookingAt());它將輸出true,因為文字的開頭abc!僅包含構詞字元。

與類別物件不同Pattern,類別物件Matcher保留狀態資訊。有時,您可能需要在模式搜尋完成後重置匹配器以清除此資訊。可以使用以下方法來重設解析器:
  • 此方法Matcher reset()重置匹配器的狀態,包括要附加到末端的位置(重設為 0)。下一個模式搜尋操作從匹配器文字的開頭開始。傳回對目前物件的參考Matcher。例如,m.reset();重置 引用的解析器m

  • 此方法Matcher reset(CharSequence text)重置解析器狀態並將新解析器文字設為text。下一個模式搜尋操作從新匹配器文字的開頭開始。傳回對目前物件的參考Matcher。例如,m.reset("new text");重置引用的解析器m並將新解析器文字設為"new text"

Java 中的正規表示式,第 3 部分 - 3

新增文字到末尾

若要附加到末端的匹配器的位置指定附加到 類型的物件末端的匹配器文字的開頭java.lang.StringBuffer。以下方法使用該位置:
  • 此方法讀取匹配器文字字元並將它們附加到參數引用的Matcher appendReplacement(StringBuffer sb, String replacement)物件的末尾。此方法在上一個模式匹配之前的最後一個字元處停止讀取。接下來,該方法將參數引用類型的物件中的字元附加到物件的末尾(字串可能包含對先前搜尋期間捕獲的文字序列的引用;這些是使用捕獲的字元和群組編號指定的)。最後,此方法將匹配器位置的值設定為附加到最後一個匹配字元的位置加一,然後傳回對目前匹配器的參考。StringBuffersbStringreplacementStringBufferreplacement($)

  • 如果匹配器尚未找到匹配項或先前的搜尋嘗試失敗,則該方法Matcher appendReplacement(StringBuffer sb, String replacement)將引發異常。如果該行指定了不在模式中的捕獲組,java.lang.IllegalStateException則會引發異常)。IndexOutOfBoundsExceptionreplacement

  • 該方法StringBuffer appendTail(StringBuffer sb)將所有文字新增至一個物件StringBuffer並傳回對該物件的參考。在最後一個方法呼叫之後appendReplacement(StringBuffer sb, String replacement),呼叫該方法appendTail(StringBuffer sb)將剩餘的文字複製到物件中StringBuffer

捕獲的群體
正如您在第 1 部分中所記得的那樣,捕獲組是括在括號 ( ()) 元字元中的字元序列。此構造的目的是儲存找到的字符,以便以後在模式匹配期間重複使用。在模式搜尋過程中,捕獲組中的所有字元都被視為一個整體。
以下程式碼呼叫appendReplacement(StringBuffer sb, String replacement)和方法appendTail(StringBuffer sb,將來源文字中出現的所有字元序列替換catcaterpillar
Pattern p = Pattern.compile("(cat)");
Matcher m = p.matcher("one cat, two cats, or three cats on a fence");
StringBuffer sb = new StringBuffer();
while (m.find())
   m.appendReplacement(sb, "$1erpillar");
m.appendTail(sb);
System.out.println(sb);
在替換文本中使用捕獲的組和對其的引用告訴程序erpillar在每次出現cat. 執行這段程式碼的結果如下所示: one caterpillar, two caterpillars, or three caterpillars on a fence

替換文字

該類別Matcher為我們提供了兩種文字替換方法,與appendReplacement(StringBuffer sb, String replacement). 使用這些方法,您可以取代第一次出現的 [replaced text] 或所有出現的內容:
  • 此方法String replaceFirst(String replacement)重置匹配器,建立一個新對象String,將匹配器文字的所有字元(直到第一個匹配項)複製到此字串,將字元從 追加到其末尾,將replacement剩餘字元複製到字串並返回物件String(該字串replacement可以包含在先前搜尋文字序列中使用美元符號和捕獲的群組編號捕獲的參考)。

  • 此方法的String replaceAll(String replacement)操作與 方法類似String replaceFirst(String replacement),但將replacement所有找到的匹配項替換為字串中的字元。

正規表示式\s+在輸入文字中搜尋一個或多個空白字元。下面,我們將使用這個正規表示式並呼叫一個方法replaceAll(String replacement)來刪除重複的空格:
Pattern p = Pattern.compile("\\s+");
Matcher m = p.matcher("Удаляем      \t\t лишние пробелы.   ");
System.out.println(m.replaceAll(" "));
結果如下: Удаляем лишние пробелы. Java 中的正規表示式,第 4 部分 Java 中的正規表示式,第 5 部分
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION