下面,我們以一個具體的有實際用處的類庫來進一步討論庫的設計方法。這個庫是jregex. (jregex.sourceforge.net)。這是一個用java實現的兼容Perl 5.6的正則表達式的庫。有很多這樣的庫, 比如gnu.regeXP,com.stevesoft.pat, 還有J2SE SDK 1.4中新增加的regex.為什么選用jregex呢?是因為 它是目前源代碼公開的regex庫中兼容Perl 5.6的正則表達式,而且剛剛更新過源代碼,并且是穩定 版,另外一個就是,它的內核算法選用了NFA(Not Finite Automata)。 要了解一個包,在看源代碼之前先應該看的就是它的API文檔。那么,看文檔的第一步應該看什么呢?當然是樹形結構。 Class Hierarchy class java.lang.Object class jregex.Matcher (implements jregex.MatchResult) class jregex.Optimizer class jregex.util.io.PathPattern class jregex.Pattern (implements jregex.REFlags, java.io.Serializable) class jregex.PerlSubstitution (implements jregex.Substitution) class jregex.Replacer class jregex.RETokenizer (implements java.util.Enumeration) class java.lang.Throwable (implements java.io.Serializable) class java.lang.Exception class java.lang.RuntimeException class java.lang.IllegalArgumentException class jregex.PatternSyntaxException class jregex.util.io.WildcardFilter (implements java.io.FilenameFilter) Interface Hierarchy interface jregex.MatchIterator interface jregex.MatchResult interface jregex.REFlags interface jregex.Substitution interface jregex.TextBuffer interface jregex.Replacer.WriterWrap 在一個正則表達式中,我們知道有兩個元素很重要,第一個就是Pattern(模式), 第二個是Matcher(匹 配結果字符串)。在jregex中,Pattern類實現了jregex.REFlags interface,和java.io.Serializable。先來看看jregex.REFlags的說明。jregex.REFlags定義了一些靜態的常量,看起來是一些標志。Pattern實現了 jregex.REFlags, 也就是說,Pattern類中包含了這些靜態的常量。 下一步,我們看看Pattern的API說明: Pattern是一個預編譯好的正則表達式的表示。要匹配一個正則表達式,先創建一個Pattern實例: Pattern p=new Pattern(myExPR); 然后取得Matcher的實例 Matcher matcher=p.matcher(myText); Matcher的實例是一個自動的匹配和搜索的對象。它提供如下方法: 搜索匹配結果: matcher.find() or matcher.findAll(); 監測是否全文匹配 : matcher.matches(); 監測是否匹配開頭 : matcher.isStart(); 帶選項的查找 : matcher.find(int options) 標志 標志(參考REFlags)改變了在預編譯的時候正則表達式符號的意義。這些標志是: REFlags.IGNORE_CASE - 忽略大小 REFlags.MULTILINE - 用^和$來表示一行文本的開頭和結尾 REFlags.DOTALL - 用.來表示回車換行 REFlags.IGNORE_SPACES - 忽略空 REFlags.UNICODE - 使用UNICODE, 即w, d不再被解釋為正則表達式的意義,而是被解釋為 UNICODE. REFlags.xml_SCHEMA - 使用XML語義。 線程 Pattern是線程安全的。也就是說,你可以在不同的線程中使用同一個Pattern的實例。 在API函數說明中,我們還能看到Pattern類的public方法。這一點將在下面有用處。先來看看構造函數: Pattern(java.lang.String regex) Compiles an expression with default flags. Pattern(java.lang.String regex, int flags) Compiles a regular expression using REFlags. Pattern(java.lang.String regex, java.lang.String flags) Compiles a regular expression using Perl5-style flags. 方法 int groupCount() How many capturing groups this expression includes? java.lang.Integer groupId(java.lang.String name) Get numeric id for a group name. Matcher matcher() Returns a targetless matcher. Matcher matcher(char[] data, int start, int end) Returns a matcher for a specified region. Matcher matcher(MatchResult res, int groupId) Returns a matcher for a match result (in a performance-friendly way). Matcher matcher(MatchResult res, java.lang.String groupName) Just as above, yet with symbolic group name. Matcher matcher(java.io.Reader text, int length) Returns a matcher taking a text stream as target. Matcher matcher(java.lang.String s) Returns a matcher for a specified string. Replacer replacer(java.lang.String expr) Returns a replacer of a pattern by specified perl-like expression. Replacer replacer(Substitution model) Returns a replacer will substitute all occurences of a pattern through applying a user-defined substitution model. RETokenizer tokenizer(char[] data, int off, int len) Tokenizes a specified region by an occurences of the pattern. RETokenizer tokenizer(java.io.Reader in, int length) Tokenizes a specified region by an occurences of the pattern. RETokenizer tokenizer(java.lang.String text) Tokenizes a text by an occurences of the pattern. java.lang.String toString_d() Returns a less or more readable representation of a bytecode for the pattern. java.lang.String toString() 接下來,我們來看看Pattern類的內容。這里有兩種方法,一種是直接閱讀源代碼,另外一種是先用工具分析一下Pattern類的內容。這里,我采用第二種方法,用javap來看類的內容。 [games]$javap -classpath .. -private jregex.Pattern Compiled from jregex/Pattern.java public class jregex.Pattern extends java.lang.Object implements java.io.Serializable, jregex.REFlags { java.lang.String stringRepr; jregex.Term root; jregex.Term root0; int memregs; int counters; int lookaheads; java.util.Hashtable namedGroupMap; private jregex.Pattern() throws jregex.PatternSyntaxException; public jregex.Pattern(java.lang.String) throws jregex.PatternSyntaxException; public jregex.Pattern(java.lang.String,java.lang.String) throws jregex.PatternSyntaxException; public jregex.Pattern(java.lang.String,int) throws jregex.PatternSyntaxException; private void compile(java.lang.String, int) throws jregex.PatternSyntaxException; public int groupCount(); public java.lang.Integer groupId(java.lang.String); public jregex.Matcher matcher(); public jregex.Matcher matcher(java.lang.String); public jregex.Matcher matcher(char[], int, int); public jregex.Matcher matcher(jregex.MatchResult, int); public jregex.Matcher matcher(jregex.MatchResult, java.lang.String); public jregex.Matcher matcher(java.io.Reader, int) throws java.io.IOException; public jregex.Replacer replacer(java.lang.String); public jregex.Replacer replacer(jregex.Substitution); public jregex.RETokenizer tokenizer(java.lang.String); public jregex.RETokenizer tokenizer(char[], int, int); public jregex.RETokenizer tokenizer(java.io.Reader, int) throws java.io.IOException; public java.lang.String toString(); public java.lang.String toString_d(); static int parseFlags(java.lang.String) throws jregex.PatternSyntaxException; static int parseFlags(char[], int, int) throws jregex.PatternSyntaxException; private static int getFlag(char) throws jregex.PatternSyntaxException; } 其中,要關心private和protected成員,因為在使用類的時候,我們只要關心public成員就行了,但 是,要閱讀源代碼,明白類的構成,就必須注重private和protected成員。 private Pattern() throws PatternSyntaxException{} public Pattern(String regex) throws PatternSyntaxException{ this(regex,DEFAULT); } public Pattern(String regex,String flags) throws PatternSyntaxException{ stringRepr=regex; compile(regex,parseFlags(flags)); } public Pattern(String regex, int flags) throws PatternSyntaxException{ stringRepr=regex; compile(regex,flags); } 可以看出,構造函數中,有一個缺省的構造函數是private。而第二個調用了最后一個構造函數,用 this()。第三個和最后一個都是用了一個函數compile來完成構造正則表達式的