`
paulwong
  • 浏览: 74372 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Regular Expression in Java

阅读更多
1. Introduction

正規表示式(Regular Expression, 以下簡稱 regexp)在文字處理方面, 已經受到廣泛的應用。而各種程式語言中也幾乎都有提供對 regexp 的支援, 廣受歡迎的 Perl 更是其中的佼佼者。在 Java SDK 1.4 版釋出之前, 若想在 Java 語言中使用 regexp, 就必需依靠由第三方提供之類別函式庫(Third-Party Class Library), 例如 The Apache Jakarta Project 提供的 Jakarta Regexp, 及 GNU Regex for Java 等. 而 Sun 也終於在 Java SDK 1.4 以來開始於其核心 API 中提供 java.util.regex.Pattern 等相關類別, 以提供C0D; regexp 的支援。本文將會介紹前述的三種 regexp package 之使用方法, 希望能提供讀者在 Java 中使用 Regular Expression 的指引。注意, 本文中並不會介紹 regexp 的語法, 若要學習 regexp, 請參考附錄。

2. java.util.regex.*

JDK 1.4 中所提供的 regex package 中只有簡單的兩個類別, Pattern 及 Matcher。但這兩個物件已經包含了所有 regexp 的功能, 請看以下的介紹:

2.1 Pattern 與 split()

Pattern 類別並沒有建構式(Constructor), 若要使用此一類別, 可運用 Pattern.compile(String regex) 方法(method)。例:

<!---->Pattern p = Pattern.compile("a*b");

注意若傳入的regexp string有錯誤, compile() 會丟出 PatternSyntaxException, 因此必需自行使用try ... catch 加以處理。
產生出 Pattern 物件後, 要如何使用呢? 先看看 Pattern 提供的方法 split()。此一方法可以將輸入字串中依符合Pattern的位置進行分段, 如:

<!---->String[] result = p.split("123aba23aabc");
    
for (int i = 0; i < result.length; i++) {
        System.out.println( (i 
+ 1+ "" + result[i]);
    }

輸出的結果為:

	1: 123
2: a23
3: c

2.2 Matcher 與 matches()

Regular Expression 的功能當然不只如此, 但是 Pattern 類別中只提供了split(), 若要進行比對(match)及取代(replace)則必需靠 Matcher 類別。例如要檢驗輸入字串是否合於Pattern, 可以使用 Pattern 中的靜態方法 matches:

<!---->System.out.println(Pattern.matches("a*b""aaaaab"));

輸出結果為:

	true

此一靜態方法是為了方便使用而提供的簡化方法, 其作用等同以下程式:

<!---->Pattern.compile("a*b").matcher("aaaaab").matches();

另外, 要注意的是, matches() 是完整字串的比對,所以 Pattern.matches("a*b", "aaaaab") 的傳回值為 true 。但是 Pattern.matches("a*b", "aaaaab1") 則會傳回否。因此, 若要在輸入字串中進行部分比對,則必需使用 Matcher 物件中提供的 method。而要如何取得 Matcher 物件呢? 方法如下:

<!---->Pattern p = Pattern.compile("a*b");
Matcher matcher 
= p.matcher("aaaaab");

Matcher 中提供了三種比對方法, 您可以依照實際需要來選擇使用:

  • matches: 完整比對, 整個輸入字串必需符合 regexp。例如前例輸入字串 "aaaaab" 完全符合 "a*b", 因此會 matches() 傳回 true.
  • lookingAt: 從輸入字串開頭比對。如前例, 若輸入字串改為 "aaaaab1" 則 matches() 會傳回 false, 而 lookingAt() 會傳回true。
  • find: 從字串中任意位置開始比對,也就是部分比對。如前例, 若輸入字串改為 "22aaaaab1" 則 matches()及lookingAt()皆傳回 false, 而 find() 則會傳回true。

2.3 replaceFirst(), replaceAll()

除了比對之外, 取代(replace)也是regexp的常見用途之一, 在 Matcher 中也提供了 replaceFirst() 及 replaceAll() 等方法進行取代。如:

<!---->Pattern p = Pattern.compile("a*b");
    Matcher matcher 
= p.matcher("123aaaaab456abcdef");
    System.out.println(matcher.replaceFirst(
"_"));    
       
//1
    matcher.reset();
       
//2
    System.out.println(matcher.replaceAll("_"));
       
//3


前例中的 1 會輸出:

123_456abcdef

只將第一個 match 的 pattern 取代為 "_", 而 3 則會輸出

123_456_cdef

將輸入字串中所有合於 pattern 的字串取代為 "_"。 請注意到 2 的部分呼叫了 matcher.reset(), 此一方法可以讓 Matcher 的比對重新開始, 也就是從輸入字串的開頭開始比對。另外, 若在程式中需要以同一個 Pattern 比對不同的輸入字串, 只需使用 reset(<input>) 方法便可以比對新的輸入字串。

2.4 gourp(), start() 及 end()

Matcher還有更進階的用法, 例如群組(Grouping), 在 Matcher 中亦有提供, 請參考以下片段:

<!---->    Pattern p = Pattern.compile("(\\w+)\\s*=\\s*(\\d+)");
    Matcher matcher 
= p.matcher("abc = 123");
    System.out.println(
"find: " + matcher.find());
    System.out.println(
"groupCount(): " + matcher.groupCount());
    
//1
    for (int i = 1; i <= matcher.groupCount(); i++) {
    
//2
      System.out.println("group(" + i + "):" + matcher.group(i)); 
      System.out.println(
"start(" + i + "):" + matcher.start(i));
      System.out.println(
"end(" + i + "):" + matcher.end(i));
    }
    matcher.reset();
    System.out.println(matcher.replaceFirst(
"$2 = $1"));
    
//3

在 regexp 中, 小括號表示群組, 可以在比對之後, 將合於 pattern 的部分紀錄起來, 以便使用 Matcher 中的 gourp() 及相關方法來應用。前例中的 1 呼叫了 groupCount(), 此處會輸出 2 表示 Pattern 中有兩個群組。迴圈 2 會依序印出各 group 的內容, 結果如下:

	group(1):abc

start(1):0

end(1):3

group(2):123

start(2):6

end(2):9

注意此處的迴圈由 1 開始, 因為 gourp(0) 所代表的是整個合於 pattern 的輸入字串, 以前例而言就是 "abc = 123", start(0) 與 end(0) 則分別為 0 與 9。
在 Matcher 提供的取代方法( replaceFirst 與 replaceAll )中, 可以使用"回溯參照", 也就是用 $n 來代表找到的群組編號, 如前例中的 3, 其輸出結果為:

123 = abc

2.5 比對參數旗標 (Matching flags)

熟悉 regexp 的讀者一定會覺得奇怪, 如何建立"與大小寫無關(Case-insensitive)" 的比對樣式呢? 又要怎麼在建立的時候, 指定讓 "." 能符合換行字元呢? 有兩種方式, 第一種方法為在建立 Pattern 物件時傳入比對參數旗標, 如:

<!---->    Pattern p = Pattern.compile("A.b", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);    //1
    Matcher matcher = p.matcher("aaa\nbbb");
    System.out.println(matcher.replaceAll(
"_"));

如此一來, 前例的輸出會是: aa_bb 另一種方法, 則是使用"內嵌式旗標(Embedded flags)", 也就是將旗標直接加在 regexp 字串中, 如前例中的 1 可以改為以下的寫法:

<!---->Pattern p = Pattern.compile("(?si)A.b");

其中的 ?s 代表單行模式(single-line mode), 也就是 Pattern.DOTALL; 而 ?i 則代表與大小寫無關, 即 Pattern.CASE_INSENSITIVE。事實上,Pattern可接受的旗標共有 7 種, 也都有其對應的內嵌式旗標, 請參考 JDK 1.4 文件。

最後, 在 JDK 1.4 中, 之前介紹的 split, matches, replaceAll 及 replaceFirst 等 regexp 功能已經整合到 String 物件中了, 例如要將 "abc123abc" 字串中所有的 "a" 或 "b" 取代為 "c", 可以使用以下敍述:

<!---->    String tmp = "abc123abc";
    String noab 
= tmp.replaceAll("(a|b)""c");

若程式中不需要使用到更進階的 regexp 功能, 便可以多加利用在 String 物件中的這些方法。詳細用法請參考 JDK 1.4 文件。

3. To be continue...

以上介紹了 JDK 1.4 中內建的 Regular Expression 類別使用方法, 下期將會介紹 Jakarta Regexp 及 GNU Regex for Java 等套件

4. 附錄:

本文所提到的套件參考文件可以在以下 URL 找到:

  1. java.util.regex API Documents, http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/package-summary.html
  2. Regular Expressions for Java, http://www.cacas.org/java/gnu/regexp/
  3. Jakarta Regexp, http://jakarta.apache.org/regexp/index.html

有關 Regular Expressions 的學習, 可以參考以下文件:
  1. Mastering Regular Expressions, http://www.oreilly.com/catalog/regex/
  2. Manual pages of Perl, perlrequick(1), perlretut(1), perlre(1)
  3. Regular Expression 簡介, http://phi.sinica.edu.tw/aspac/reports/94/94019/
  4. 一輩子受用的 Regular Expressions -- 兼談另類的電腦學習態度, http://www.cyut.edu.tw/~ckhung/b/gnu/regexp.shtml
  5. A Tao of Regular Expressions (正規表示式之道) http://sitescooper.org/tao_regexps.html
分享到:
评论

相关推荐

    Coding Interview In Java

    10 Regular Expression Matching in Java 39 11 Merge Intervals 43 12 Insert Interval 45 13 Two Sum 47 14 Two Sum II Input array is sorted 49 15 Two Sum III Data structure design 51 16 3Sum 53 17 4Sum 55...

    Mastering Regular Expressions, 3rd Edition

    They are now standard features in a wide range of languages and popular tools, including Perl, Python, Ruby, Java, VB.NET and C# (and any language using the .NET Framework), PHP, and MySQL....

    Jeffrey E. F. Friedl - Mastering.Regular.Expressions.3rd.Edition

    Mastering Regular Expressions, Third Edition, now includes a full chapter devoted to PHP and its powerful and expressive suite of regular expression functions, in addition to enhanced PHP coverage in ...

    Core Java Volume II Advanced Features__10th edition

    •Work with Java SE 8’s regular expression package •Make the most of XML in Java: parsing, validation, XPath, document generation, XSL, and more •Efficiently connect Java programs to network ...

    LeetCode题解(java语言实现).pdf

    * Regular Expression Matching in Java:该题目要求匹配字符串和正则表达式,实现方法使用了动态规划算法。 * Merge Intervals:该题目要求合并重叠的区间,实现方法使用了排序和迭代算法。 * Insert Interval:该...

    Python_Regular_Expressions_-_Learn_Python_Regular_Expressions_in_an_Easy_Way.pdf.pdf

    文档《Python_Regular_Expressions_-_Learn_Python_Regular_Expressions_in_an_Easy_Way.pdf.pdf》的核心内容旨在帮助读者快速掌握Python中正则表达式的基础和高级应用。本书内容详实,不仅包括基础知识,还包括...

    Java IO, NIO and NIO.2(Apress,2015)

    Next, you'll learn about NIO's buffer, channel, selector, regular expression, charset, and formatter APIs. Finally, you'll discover NIO.2's offerings in terms of an improved file system interface, ...

    LeetCode题解 - Java语言实现-181页.pdf

    8. Regular Expression Matching in Java 正则表达式匹配是一个字符串问题,要求使用正则表达式来匹配字符串。可以使用Java的Pattern和Matcher类来解决该问题。 9. Merge Intervals 区间合并是一个数组问题,要求...

    RegularExpressionTester:在网站上测试Java正则表达式

    RegularExpressionTester 这是Java正则表达式的测试工具支持在...you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICE

    JAVA_split_用法

    此方法利用正则表达式(Regular Expression)作为分隔符来分割字符串,并允许设定分割后的数组的最大长度。 #### split() 方法签名 `split()`方法有两个主要重载版本: 1. `public String[] split(String regex)` ...

    javasnmp源码-DevOps-Interview:DevOps-面试

    java snmp源码DevOps-面试 去做 IO性能调优 Linux 命令 1. sed - Replace the first occurrence of a regular expression in each line of a file, and print the result: sed ' s/{{regex}}/{{replace}}/ ' {{...

    regular-expression-in-hy:Hy python正则表达式

    我使用hylang进行正则表达式,但这并不意味着javascript / java / python中的regx不好(它们已经足够好了!),并且我不想替换它们。 这只是为了显示lisp函数编程的便利性。 好了,现在我实现了一个使用hy(python...

    java_技术参考汇集

    正则表达式(Regular Expression)是一种模式匹配工具,用于字符串处理,如搜索、替换和提取等操作。在Java中,你可以使用java.util.regex包中的Pattern和Matcher类来处理正则表达式。例如,创建一个Pattern对象,...

    java笔记之正则表达式

    首先,正则表达式(Regular Expression)是一组符合特定规则的字符序列,主要用于字符串的查找、匹配、替换等操作。它们的特点在于使用特殊符号来简化字符串处理的代码,使代码更简洁,但也可能导致可读性降低,特别...

    Addison.Wesley.The.Java.Programming.Language.4th.Edition.Aug.2005.chm

    the underlying character set support, and the powerful utilities for regular expression matching. &lt;br&gt;Chapter 14Threadsexplains the language's view of multithreading. Many applications, such as ...

    ibatis例子加教程&java&javascript&dhtml&正则表达式工具

    正则表达式(Regular Expression)是一种用于模式匹配的字符串处理工具。它用于在文本中查找、替换或提取符合特定模式的字符串。正则表达式在各种编程语言和文本编辑器中都有广泛的应用,如在Java、JavaScript中,...

Global site tag (gtag.js) - Google Analytics