程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Merlin的魔力: 用新的正則表達式庫解析字符序列

Merlin的魔力: 用新的正則表達式庫解析字符序列

編輯:關於JAVA

解析模式的文本字符串

正則表達式是根據文本匹配模式的方法 ― 類似於編譯器生成類文件的工作原理。編譯器在源代碼中查找各種模式以便將源代碼表達式轉換為字節碼。通過識別這些源代碼模式,編譯器能夠只將有效的源代碼表示轉換為已編譯的類文件。

什麼是模式?

在正則表達式的上下文中,模式是字符序列的文本表示法。例如,如果您想知道一個字符序列中是否存在 car這個詞,您會使用模式 car,因為這是精確地表示該字符串的方法。對於更復雜的模式,您可以使用特殊字符作為占位符。如果您不是要搜索 car,而是想搜索以字母 c開頭並以字母 r結尾的任何文本字符串,您會使用 c*r模式,其中 *代表第一個 r前的任意多個字符。 c*r模式將匹配任何以 c開頭並以 r結尾的字符串,如 cougar、 cavalier或 chrysler。

如何指定模式表達式

模式匹配的主要部分是關於要使用什麼樣的表達式。 Pattern 先保存要使用的表達式,然後將其傳遞給 Matcher 類以便在字符序列的上下文中檢查其匹配情況。例如,如果您想驗證一個電子郵件地址,您可能要檢查用戶輸入是否與這樣一個模式匹配 ― 它包含一個字母數字序列,後跟一個 @ 符號,@ 後又跟兩組用句點隔開的字符。這可以用表達式 \p{Alnum}+@\w+\.\p{Alpha}{2,3} 來表示。(是的,這過於簡化了電子郵件地址的結構,可能會排除某些有效的電子郵件地址,但它作為示例已經足夠了。)

在討論模式語言的具體細節之前,我們來仔細看一下 \p{Alnum}+@\w+\.\p{Alpha}{2,3} 。 \p{Alnum} 序列表示單個字母數字字符(A 到 Z、a 到 z 或 0 到 9)。 \p{Alnum} 後面的加號(+)被稱為 量詞(quantifier)。它被應用在表達式的前面部分,表示 \p{Alnum} 必須出現一次或更多次。使用星號(*)表示要出現零次或一次以上(含一次)。@ 就是意味著它必須出現在至少一個字母數字字符之後,這樣整個模式匹配才能成功。 \w+ 與 \p{Alnum}+ 類似,但添加了下劃線(_)。某些序列有多個表達式。反斜槓(\ .)代表句點。如果前面沒有反斜槓,單獨一個句點代表任意字符。最後的 \p{Alpha}{2, 3} 表示兩個或三個字母字符。

只要學會了規范語言,您就能掌握模式的所有秘密。我們來看一些更常用的表達式的種類:

文字(Literal):表達式內任何不具有特殊意義的字符都被看作是一個文字,並與自身匹配。

量詞(Quantifier):某些字符或表達式,它們被用來計算一個文字或分組可以在字符序列中出現的次數,以便該序列與表達式匹配。分組是由圓括號內的一組字符指定的。

? 表示出現一次或根本不出現

* 表示出現零次或一次以上(含一次)

+ 表示出現一次或多次

字符類(Character class):一個字符類就是方括號內的一個字符集,其中,匹配可以是括號內的任意一個字符。您可以把字符類與量詞結合在一起,例如, [acegikmoqsuwy]* 將是只包含字母表中奇數字母的任意字符序列。某些字符類是預先定義的:

\d ― 數字(0 到 9)

\D -- 非數字

\s -- 空白字符,如制表符或換行符

\S -- 非空白字符

\w -- 單字字符(a 到 z、A 到 Z、0 到 9 以及下劃線)

\W -- 非單字字符(其它任意字符)

Posix 字符類(Posix character class):某些字符類僅在用於 US-ASCII 比較時才有效。例如:

\p{Lower} ― 小寫字符

\p{Upper} ― 大寫字符

\p{ASCII} ― 所有 ASCII 字符

\p{Alpha} ― 字母字符(\p{Lower} 與 \p{Upper} 相結合)

\p{Digit} ― 從 0 到 9 的數字

\p{Alnum} ― 字母數字字符

范圍(Range):使用短線(dash)來指定包括一定范圍字符的字符類。例如, [A-J] 表示從 A 到 J 的大寫字母。

否定(Negation):脫字符(^)否定字符類的內容。例如, [^A-J] 表示除 A 到 J 之外的任何字符。

請參閱 Pattern API 文檔(可以從 參考資料找到)了解關於序列的其它詳細信息。

如何有效地使用模式

既然您已經了解了如何指定模式,我們就來使用它們吧。您需要讓 Pattern 類編譯它們,如下所示。注意,反斜槓字符(\)在 String 常量中需要轉義。

Pattern pattern = Pattern.compile(
"\\p{Alnum}+@\\w+\\.\\p{Alpha}{2,3}");

有了一個編譯好的模式後,您可以使用 Pattern 類根據模式把一個輸入行分割為一系列單字,或者使用 Matcher 類執行一些更復雜的任務。下面說明了如何分割輸入字符序列,其中使用的模式指定了分隔符,而不是字:

String words[] = pattern.split(input);

如果您想在一個字符序列中多次匹配一個模式,上面的代碼片段是一個很好的起點。但如果您想獲取特定的輸入,您將需要 Pattern 的 matcher() 方法。在給定某個輸入時,這個方法將返回適當的 Matcher 類。接著,您使用 Matcher 實例遍歷整個結果在輸入序列中查找不同的模式匹配,或者使用 Matcher 實例作為查找-替換工具(後一種方法更好):

Matcher matcher = pattern.matcher(input);

要根據整個序列匹配模式,請使用 matches() 。要確定是否只有序列的一部分匹配,請使用 find() :

if (matcher.find()) {
   // Found some string within input sequence
   // That matched the compiled pattern
   String match = matcher.group();
   // Process matching pattern
}

完整的示例

這兩個類( Pattern 與 Matcher )就是整個模式匹配庫。提出正確的正則表達式,然後使用 Matcher 類的結果,這就是這個模式匹配庫要做的全部工作。在針對 Java 語言的關於正則表達式的專門書籍出現之前,請找一本關於 Perl 的好書來進一步了解特定的模式。清單 1 提供了一個完整的示例,該示例將在特定文件中查找從命令行作為輸入而傳入的最長單詞。

清單 1.“最長的單詞”示例

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.util.*;
import java.util.regex.*;
public class Longest {
  public static void main(String args[]) {
    if (args.length != 1) {
      System.err.println("Provide a filename");
      return;
    }
    try {
      // Map File from filename to byte buffer
      FileInputStream input =
        new FileInputStream(args[0]);
      FileChannel channel = input.getChannel();
      int fileLength = (int)channel.size();
      MappedByteBuffer buffer = channel.map(
        FileChannel.MapMode.READ_ONLY, 0, fileLength);
      // Convert to character buffer
      Charset charset = Charset.forName("ISO-8859-1");
      CharsetDecoder decoder = charset.newDecoder();
      CharBuffer charBuffer = decoder.decode(buffer);
      // Create line pattern
      Pattern linePattern =
        Pattern.compile(".*$", Pattern.MULTILINE);
      // Create word pattern
      Pattern wordBreakPattern =
        Pattern.compile("[\\p{Punct}\\s}]");
      // Match line pattern to buffer
      Matcher lineMatcher =
        linePattern.matcher(charBuffer);
      // Holder for longest word
      String longest = "";
      // For each line
      while (lineMatcher.find()) {
        // Get line
        String line = lineMatcher.group();
        // Get array of words on line
        String words[] = wordBreakPattern.split(line);
        // Look for longest word
        for (int i=0, n=words.length; i<n; i++) {
          if (words[i].length() > longest.length()) {
            longest = words[i];
          }
        }
      }
      // Report
      System.out.println("Longest word: " + longest);
      // Close
      input.close();
    } catch (IOException e) {
      System.err.println("Error processing");
    }
  }
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved