查看文章 |
java正则表达式; regular expression(2)
2007-06-26 08:40
4. java RegexDemo a{2} aababbaaaab: 使用greedy quantifier 来匹配中的每一个 aababbaaaab中的 aa序列。以下是输出结果: Regex = a{2} Text = aababbaaaab Found aa starting at index 0 and ending at index 2 Found aa starting at index 6 and ending at index 8 Found aa starting at index 8 and ending at index 10 5. java RegexDemo a{2,} aababbaaaab: 使用了greedy quantifier 来匹配在ababbaaaab中两个或更多的匹配,以下是输出结果: Regex = a{2,} Text = aababbaaaab Found aa starting at index 0 and ending at index 2 Found aaaa starting at index 6 and ending at index 10 6. java RegexDemo a{1,3} aababbaaaab: 使用greedy quantifier 来匹配在aababbaaaab中出现的a、aa或者aaa。以下是输出结果: Regex = a{1,3} Text = aababbaaaab Found aa starting at index 0 and ending at index 2 Found a starting at index 3 and ending at index 4 Found aaa starting at index 6 and ending at index 9 Found a starting at index 9 and ending at index 10 7. java RegexDemo a+? abaa: 使用一个reluctant quantifier 在abaa中一次或多次匹配a。以下是输出结果: Regex = a+? Text = abaa Found a starting at index 0 and ending at index 1 Found a starting at index 2 and ending at index 3 Found a starting at index 3 and ending at index 4 不像在第三个例中的greedy变量,reluctant 示例产生了三个单独的匹配,因为reluctant quantifier尽力的查找最短的匹配。 8. java RegexDemo .*+end "This is the end": 使用了possessive quantifier 来匹配在this is the end中的以end结尾的任意字符0次或者多次。以下是输出结果: Regex = .*+end Text = This is the end 由于这个possessive quantifier consume了整个文本,没有留下任何东西来匹配end,它没有产生匹配。相比之下,在java RegexDemo .*end "This is the end" 的greedy quantifier,因为它每次backing off一个字符直到最右端的end匹配,产生了一个匹配。(这个quantifier与greedy的不同就在后者的匹配过程中一旦匹配的字符,在随后的匹配中就不再使用。因此.*这部分正则表达式就匹配了全部的字符串,就没有字符可以与end匹配了。) Boundary matchers 我们有时想在一行的开始、在单词的边界、文本的结束等等匹配pattern。使用 boundary matcher,一个指定了匹配边界的正则表达式结构,完成这个任务。Table 2 表示了Pattern的边界匹配支持。 Table 2. Boundary matchers Boundary Matcher Description ^ 一行的开始 $ 一行的结束 \b 单词的边界 \B 非单词边界 \A 文本的开始 \G 前一个匹配的结束 \Z The end of the text (but for the final line terminator, if any) \z 文本结束 下边的命令行示例使用了^ 边界匹配元字符 ensure 由零个或者多个字符跟随的行开始。 java RegexDemo ^The\w* Therefore ^ 指出了前三个字符必须匹配pattern后的T、h和e字符。可跟随任意数量的字符。以上的命令行产生以下输出: Regex = ^The\w* Text = Therefore Found Therefore starting at index 0 and ending at index 9 把命令行改为java RegexDemo ^The\w* " Therefore"。发生了什么事?因为在therefore前的一个空格,没有匹配被发现。 Embedded flag expressions Matcher假设了确定的却省值,例如大小写敏感的匹配。一个程序可以使用an embedded flag expression 来覆盖缺省值,也就是,使用一个正则表达式结构,圆括号元字符包围一个问号元字符后跟小写字母。Pattern认可以下的embedded flag expressions : (?i): enables 大小写不敏感的pattern 匹配。例如:java RegexDemo (?i)tree Treehouse 来匹配tree和Tree。大小写敏感是缺省值。 (?x): 允许空格和注释用#元字符开始出现在Pattern中。一个matcher 忽略全部它们。例如:java RegexDemo ".at(?x)#match hat, cat, and so on" matter 匹配.at和mat。缺省地,空格和注释式不被允许的;一个matcher 将它们考虑为对match有贡献的字符。 (?s): 使dotall 方式有效。在这种模式中,句点除了其它字符外还匹配text结束。 例如:java RegexDemo (?s). \n ,. 匹配了 \n。Nondotall 方式是缺省的:不匹配行结尾。 (?m): 使多行方式有效。在多行模式下 ^ and $ 恰好分别的在一行的终结或末端之后或者之前。例如:java RegexDemo (?m)^.ake make\rlake\n\rtake 匹配 .ake 和 make、 lake与 take。非多行模式是缺省的: ^ and $ match仅在整个文本的开始和结束。 (?u): enables Unicode-aware case folding. This flag works with (?i) to perform case-insensitive matching in a manner consistent with the Unicode Standard. The default: case-insensitive matching that assumes only characters in the US-ASCII character set match。 (?d): enables Unix lines mode. In that mode, a matcher recognizes only the \n line terminator in the context of the ., ^, and $ metacharacters. Non-Unix lines mode is the default: a matcher recognizes all terminators in the context of the aforementioned metacharacters。 Embedded flag expressions 类似于 capturing groups因为两个regex constructs都用圆括号包围字符。不像capturing group,embedded flag expression 没有捕获匹配的字符。因而,一个embedded flag expression是noncapturing group的特例。也就是说,一个不捕获text字符的regex construct ;它指定了由元字符圆括号包围的字符序列。在Pattern's SDK 文档中出现了一些noncapturing groups。 Tip 为了在正则表达式中指定多个embedded flag 表达式。或者吧它们并排的放在一起 (e.g., (?m)(?i)) 或者 把它们的小写字母并排的放在一起 (e.g., (?mi))。 探索java.util.regex 类的方法 java.util.regex包的三个类提供了为帮我书写更健壮的正则表达式代码和创建强大的text处理工具许多的方法。 我们从Pattern类开始探索这些方法。 Note 你也可以explore CharSequence 接口的当你创建一个新的字符序列类要实现的方法。仅实现 CharSequence 接口的类是java.nio.CharBuffer, String, 和 StringBuffer。 Pattern 方法 除非代码将一个string编译为Pattern对象一个regex表达式式没有用处的。用以下编辑方法中的一个完成这个任务: public static Pattern compile(String regex): 将regex内容编译为在一个新的Pattern对象内存储的树状结构的对象表示。返回那个对象引用。例如:Pattern p = Pattern.compile ("(?m)^\\.");创建了一个,存储了一个编译的表示了匹配以句点开始的行的表示。 public static Pattern compile(String regex, int flags): 完成前一个方法的相同任务。然而,它同时考虑包含了flag常量(flags指定的)。Flag常量在Pattern中(except the canonical equivalence flag, CANON_EQ)被作为二选一的embedded flag expressions被声明。例如:Pattern p = Pattern.compile ("^\\.", Pattern.MULTILINE);和上一个例子等价,Pattern.MULTILINE 常量和the (?m) embedded flag 表达式完成相同的任务。(参考SDK's Pattern 文档学习其它的常量。) 假如不是这些在Pattern中被定义的常量在flag中出现,方法将抛出IllegalArgumentException 异常。 假如需要,通过调用以下方法可以得到一个Pattern对象的flag和最初的被编译为对象的正则表达式: public int flags(): 返回当正则表达式编译时指定的Pattern的flag。例如:System.out.println (p.flags ()); 输出p引用的的Pattern相关的flag。 public String pattern(): 返回最初的被编译进Pattern的正则表达式。例如:System.out.println (p.pattern ()); 输出对应p引用Pattern的正则表达式。(Matcher 类包含了类似的返回Matcher相关的Pattern对象的Pattern pattern() 方法。) 在创建一个Pattern对象后,你一般的通过调用Pattern的公有方法matcher(CharSequence text)获得一个Matcher对象。这个方法需要一个简单的,实现了CharSequence接口的文本对象参数。获得的对象在pattern匹配的过程中扫描输入的文本对象。例如:Pattern p = Pattern.compile ("[^aeiouy]"); Matcher m = p.matcher ("This is a test."); 获得一个在text中匹配所有非元音字母的matcher。 当你想检查一个pattern是否完全的匹配一个文本序列的时候创建Pattern和Matcher对象是令人烦恼的。幸运的是,Pattern提供了一个方便的方法完成这个任务;public static boolean matches(String regex, CharSequence text)。当且仅当整个字符序列匹配regex的pattern的场合下静态方法返回布尔值true。例如:System.out.println (Pattern.matches ("[a-z[\\s]]*", "all lowercase letters and whitespace only"));返回布尔值true, 指出仅空格字符和小写字符在all lowercase letters and whitespace only中出现。 书写代码将text分成它的组成部分(例如雇员记录文件到一个字段的set) 是许多开发者发现乏味的任务。Pattern 通过提供一对字符分割方法来减轻那种tedium。 public String [] split(CharSequence text, int limit): 分割在当前的Pattern对象的pattern匹配周围的text。这个方法返回一个数组,它的每一个条目指定了一个从下一个由pattern匹配(或者文本结束)分开的字符序列;且所有条目以它们在text中出现相同的顺序存储。书组条目的数量依赖于limit,它同时也控制了匹配发生次数。一个正数意味着,至多,limit-1 个匹配被考虑且数组的长度不大于限定的条目数。一个负值以为着所有匹配的可能都被考虑且数组可以任意长。一个0值以为着所有可能匹配的条目都被考虑,数组可以有任意的长度,且尾部的空字符串被丢弃。 public String [] split(CharSequence text): 用0作为限制调用前边方法,返回方法调用的结果。 假如你想一个拆分雇员记录,包含了姓名,年龄,街道和工资,为它的组成部分。以下的代码用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]); The code fragment above specifies a regex that matches a comma character immediately followed by a single-space character and produces the following output: John Doe 47 Hillsboro Road 32000 Note String合并了三个方便的方法调用它们等价的Pattern方法: public boolean matches(String regex), public String [] split(String regex), and public String [] split(String regex, int limit)。 Matcher 方法 Matcher对象支持不同类型的pattern匹配操作,例如扫描text查找下一个match;尝试根据一个pattern来匹配整个文本;根据一个pattern尝试匹配部分text。用以下的方法完成这些任务: public boolean find(): 扫描text查找下一个match。此方法,或者在text的开始扫描,假如上一次的方法调用返回true且这个matcher没有被reset,在前一个match后的第一个字符开始扫描。假如一个match被找到的话返回布尔值true。Listing 1 展示了一个例子。 public boolean find(int start): 重新安排matcher扫描下一个match。扫描从start指定的index开始。假如一个match被找到的话返回布尔值true。例如:m.find (1); 从index1开始扫描。(索引0被忽略。)假如start包含了一个负数或者一个超出了matcfher的text长度的值,这个方法抛出IndexOutOfBoundsException异常。 public boolean matches(): 尝试根据pattern匹配整个text。在这个text匹配的情形下返回true。例如: Pattern p = Pattern.compile ("\\w*"); Matcher m = p.matcher ("abc!"); System.out.println (m.matches ()); 输出false因为整个abc! text 包含了非字母word characters。 public boolean lookingAt(): 尝试根据pattern匹配text。假如一个match被找到的话返回布尔值true。 不像 matches(), 整个text不需要被匹配。例如:Pattern p = Pattern.compile ("\\w*"); Matcher m = p.matcher ("abc!"); System.out.println (p.lookingAt ()); 输出true因为text abc!的开始部分仅包含word 字符。 不像Pattern对象,Matcher 包含了状态信息。有时,你在一个pattern 匹配后想reset一个matcher清除那些信息。下边的方法reset了一个matcher: public Matcher reset(): 重置了一个matcher的状态,包括matcher的append position(被清除为0)。下一个pattern的匹配操作从matcher新文本的起始开始。返回当前的matcher对象引用。例如:m.reset (); 通过引用m重置了matcher。 public Matcher reset(CharSequence text): 重新设置一个matcher的状态且设置了matcher的文本内同。下一个pattern的匹配操作在matcher新的文本的起始位置开始。返回当前的matcher对象引用。例如:m.reset ("new text"); 重置m引用的对象并制定 新的text作为matcher的新text。 一个matcher的append position 决定了matcher的text的追加到一个StringBuffer对象中的开始位置。以下的方法使用了append position: public Matcher appendReplacement(StringBuffer sb, String replacement): 读取matcher的text并将它们追加到sb引用的StringBuffer对象。这个方法在前一个pattern match的最后一个字符之后停止读取。此method 然后添加replacement引用的中的characters 到StringBuffer 对象。(替换字符串可以包含上一个匹配捕获的文本的引用,通过dollar-sign characters ($) 和 capturing group 数) 最终,这个方法设置了matcher的append position为最后一个匹配字符的位置加上1。一个当前的matcher对象的引用返回。假如这个matcher对象还没有执行match或者上次的match尝试失败此方法将抛出一个IllegalStateException 异常。假如replacement指定了一个pattern中不存在的capturing group 一个IndexOutOfBoundsException异常将被抛出。 public StringBuffer appendTail(StringBuffer sb): 追加所有的text 到StringBuffer对象并返回对象引用。在最后一次调用appendReplacement(StringBuffer sb, String replacement) 方法之后,调用appendTail(StringBuffer sb) copy剩余的text到StringBuffer对象。 随后的例子调用appendReplacement(StringBuffer sb, String replacement) 和 appendTail(StringBuffer sb) 方法来替换所有在one cat, two cats, or three cats on a fence 中出现的cat为caterpillar。一个capturing group 和 在replacement中的capturing group的引用允许在每一个cat匹配后插入erpillar: 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); 此示例产生如下输出: one caterpillar, two caterpillars, or three caterpillars on a fence 其它的两个替换方法使用替换的文本替换第一个match和所有的match成为可能: public String replaceFirst(String replacement): 重置matcher,创建一个新的String对象,拷贝所有匹配的文本字符(直到第一个match)到String,追加替换字符到String,拷贝剩余的字符到Strring,并返回对象引用。(替换字符串可以包含上一个匹配捕获的文本的引用,通过dollar-sign characters ($) 和 capturing group 数。) public String replaceAll(String replacement): 操作和上一个方法类似。然而,replaceAll(String replacement) 用替换字符替换所有匹配。 正则表达式\s+ 探测在文本中出现的一次或多次出现的空格。随后的例子使用了这个regex 并调用了replaceAll(String replacement) 方法来从text删除duplicate whitespace : Pattern p = Pattern.compile ("\\s+"); Matcher m = p.matcher ("Remove the \t\t duplicate whitespace. "); System.out.println (m.replaceAll (" ")); 此示例产生如下输出: Remove the duplicate whitespace. Listing 1 包含了System.out.println ("Found " + m.group ());. 注意方法调用group()。此方法是capturing group-oriented 的Matcher方法: public int groupCount(): 返回在matcher的pattern中capturing groups 的个数。这个计数没有包含特定的capturing group 数字 0,它捕获前一个match(不管一个pattern包含capturing groups与否。) public String group(): 通过capturing group 数字 0记录返回上一个match的字符。此方法可以根据一个空的字符串返回一个空字符串。假如match还没有被尝试或者上次的match操作失败将抛出IllegalStateException异常。 public String group(int group): 像上一个方法,除了通过group指定的capturing group number返回以前的match字符外。假如没有group number 指定的capturing group在pattern中存在,此方法抛出 一个IndexOutOfBoundsException 异常。 以下代码示范了the capturing group 方法: Pattern p = Pattern.compile ("(.(.(.)))"); Matcher m = p.matcher ("abc"); m.find (); System.out.println (m.groupCount ()); for (int i = 0; i <= m.groupCount (); i++) System.out.println (i + ": " + m.group (i)); The example produces the following output: 3 0: abc 1: abc 2: bc 3: c Capturing group 数字0 保存了previous match 且与has nothing to do with whether 一个capturing group在一个pattern中出现与否没有任何关系。也就是 is (.(.(.)))。其它的三个capturing groups捕获了previous match属于这个capturing groups的字符。例如,number 2, (.(.)), 捕获 bc; and number 3, (.), 捕获 c. 在我们离开讨论Matcher的方法之前,我们将examine四个match位置方法: public int start(): 返回previous match的开始位置。假如match还没有被执行或者上次的match失败,此方法抛出一个IllegalStateException异常。 public int start(int group): 类似上一个方法,除了返回group指定的capturing group 的相关的previous match 的开始索引外,假如在pattern中没有指定的capturing group number 存在,start(int group) 抛出IndexOutOfBoundsException 异常。 public int end(): 返回上次match中匹配的字符的索引位置加上1。假如match还没有被尝试或者上次的match操作失败将抛出IllegalStateException异常。 public int end(int group): 类似上一个方法,除了返回group指定的capturing group 的相关的previous match 的end索引外。假如在pattern中没有指定的capturing group number 存在,end(int group) 抛出IndexOutOfBoundsException 异常。 下边的示例示范了两个match position 方法,为capturing group number 2报告起始/结束match 位置: Pattern p = Pattern.compile ("(.(.(.)))"); Matcher m = p.matcher ("abcabcabc"); while (m.find ()) { System.out.println ("Found " + m.group (2)); System.out.println (" starting at index " + m.start (2) + " and ending at index " + m.end (2)); System.out.println (); } The example produces the following output: Found bc starting at index 1 and ending at index 3 Found bc starting at index 4 and ending at index 6 Found bc starting at index 7 and ending at index 9 输出show我们仅仅对与capturing group number 2相关的matcher感兴趣,也就是这些匹配的起始结束位置。 Note String 引入了两个方便的和调用Matcher等价的方法:public String replaceFirst(String regex, String replacement) 和 public String replaceAll(String regex, String replacement)。 PatternSyntaxException methods Pattern的方法当它们发现非法的正则表达式语法错误的时候抛出PatternSyntaxException 异常。一个异常处理器可以调用PatternSyntaxException 的方法来获得抛出的关于语法错误的PatternSyntaxException 对象的信息。 public String getDescription(): 返回语法错误描述。 public int getIndex(): 返回语法错误发生位置的近似索引或-1,假如index是未知的。 public String getMessage(): 建立一个多行的,包含了其它三个方法返回的信息的综合,以可视的方式指出在pattern中错误的位置字符串。 public String getPattern(): 返回不正确的正则表达式。 因为PatternSyntaxException 从java.lang.RuntimeException继承而来,代码不需要指定错误handler。This proves appropriate when regexes are known to have correct patterns。但当有潜在的pattern语法错误存在的时候,一个异常handler是必需的。因而,RegexDemo的源代码(参看 Listing 1) 包含了try { ... } catch (ParseSyntaxException e) { ... },它们调用了PatternSyntaxException四个异常方法中的每一个来获得非法pattern的信息。 什么组成了非法的pattern?在embedded flag expression 中没有指定结束的元字符结束符号就是一个例。假如你执行java RegexDemo (?itree Treehouse。此命令的非法正则表达式(?tree pattern 导致 p = Pattern.compile (args [0]); 抛出PatternSyntaxException 异常。你将看到如下输出: Regex syntax error: Unknown inline modifier near index 3 (?itree ^ Error description: Unknown inline modifier Error index: 3 Erroneous pattern: (?itree Note public PatternSyntaxException(String desc, String regex, int index) 构造函数让你创建你自己的PatternSyntaxException对象, That constructor comes in handy should you ever create your own preprocessing compilation method that recognizes your own pattern syntax, translates that syntax to syntax recognized by Pattern's compilation methods, and calls one of those compilation methods. If your method's caller violates your custom pattern syntax, you can throw an appropriate PatternSyntaxException object from that method。 一个正则表达式应用实践 Regexes let you create powerful text-processing applications. One application you might find helpful extracts comments from a Java, C, or C++ source file, and records those comments in another file. Listing 2 presents that application's source code: Listing 2. ExtCmnt.java // ExtCmnt.java import java.io.*; import java.util.regex.*; class ExtCmnt { public static void main (String [] args) { if (args.length != 2) { System.err.println ("usage: java ExtCmnt infile outfile"); return; } Pattern p; try { // The following pattern lets this extract multiline comments that // appear on a single line (e.g., /* same line */) and single-line // comments (e.g., // some line). Furthermore, the comment may // appear anywhere on the line. p = Pattern.compile (".*/\\*.*\\*/|.*//.*$"); } catch (PatternSyntaxException e) { System.err.println ("Regex syntax error: " + e.getMessage ()); System.err.println ("Error description: " + e.getDescription ()); System.err.println ("Error index: " + e.getIndex ()); System.err.println ("Erroneous pattern: " + e.getPattern ()); return; } BufferedReader br = null; BufferedWriter bw = null; try { FileReader fr = new FileReader (args [0]); br = new BufferedReader (fr); FileWriter fw = new FileWriter (args [1]); bw = new BufferedWriter (fw); Matcher m = p.matcher (""); String line; while ((line = br.readLine ()) != null) { m.reset (line); if (m.matches ()) /* entire line must match */ { bw.write (line); bw.newLine (); } } } catch (IOException e) { System.err.println (e.getMessage ()); return; } finally // Close file. { try { if (br != null) br.close (); if (bw != null) bw.close (); } catch (IOException e) { } } } } 在创建Pattern 和Matcher 对象之后,ExtCmnt 逐行的读取一个文本文件的内容。对于每一行,matcher尝试匹配pattern的行,鉴别是一个单行的注释或者多行的注释在一行中出现。假如一行匹配pattern,ExtCmnt 将此行写入另外一个文本文件中。例如,java ExtCmnt ExtCmnt.java out 读取ExtCmnt.java 文件的每一行,根据pattern来尝试着一行,将匹配的行输出到名叫out的文件。 (不要担心理解文件的读写逻辑。我将在将来的文章中explore这些代码。) 在ExtCmnt执行完成,out 文件包含了以下行: // ExtCmnt.java // The following pattern lets this extract multiline comments that // appear on a single line (e.g., /* same line */) and single-line // comments (e.g., // some line). Furthermore, the comment may // appear anywhere on the line. p = Pattern.compile (".*/\\*.*\\*/|.*//.*$"); if (m.matches ()) /* entire line must match */ finally // Close file. 这个输出显示ExtCmnt 并不完美:p = Pattern.compile (".*/\\*.*\\*/|.*//.*$"); 没有描绘一个注释。出现在out中的行因为ExtCmnt的matcher匹配了//字符。 关于pattern ".*/\\*.*\\*/|.*//.*$"由一些有趣的事,竖线元字符metacharacter (|)。依照SDK documentation,圆括号元字符在capturing group和 竖线元字符是逻辑操作符号。vertical bar 描述了一个matcher,它使用操作符左侧的正则表达式结构来在matcher的文本中定为一个match。假如没有match存在,matcher使用操作符号右侧的正则表达式进行再次的匹配尝试。 温习 尽管正则表达式简化了在text处理程序中pattern匹配的代码,除非你理解它们,否则你不能有效的在你的程序中使用正则表达式。这篇文章通过介绍给你regex terminology,the java.util.regex 包和示范regex constructs的程序来让你对正则表达式有一个基本的理解。既然你对regexes有了一个基本的理解,建立在通过阅读additional articles (see Resources)和学习java.util.regex's SDK 文档,那里你可以学习更多的regex constructs ,例如POSIX (Portable Operating System Interface for Unix) 字符类。 我鼓励你用这篇文章中或者其它以前文章中资料中问题email me。(请保持问题和这个栏目讨论的文章相关性。)你的问题和我的回答将出现在相关的学习guides中。) After writing Java 101 articles for 28 consecutive months, I'm taking a two-month break. I'll return in May and introduce a series on data structures and algorithms. About the author Jeff Friesen has been involved with computers for the past 23 years. He holds a degree in computer science and has worked with many computer languages. Jeff has also taught introductory Java programming at the college level. In addition to writing for JavaWorld, he has written his own Java book for beginners—Java 2 by Example, Second Edition (Que Publishing, 2001; ISBN: 0789725932)—and helped write Using Java 2 Platform, Special Edition (Que Publishing, 2001; ISBN: 0789724685). Jeff goes by the nickname Java Jeff (or JavaJeff). To see what he's working on, check out his Website at http://www.javajeff.com. Resources Download this article's source code and resource files: http://www.javaworld.com/javaworld/jw-02-2003/java101/jw-0207-java101.zip For a glossary specific to this article, homework, and more, see the Java 101 study guide that accompanies this article: http://www.javaworld.com/javaworld/jw-02-2003/jw-0207-java101guide.HTML "Magic with Merlin: Parse Sequences of Characters with the New regex Library," John Zukowski (IBM developerWorks, August 2002) explores java.util.regex's support for pattern matching and presents a complete example that finds the longest word in a text file: http://www-106.ibm.com/developerworks/java/library/j-mer0827/ "Matchmaking with Regular Expressions," Benedict Chng (JavaWorld, July 2001) explores regexes in the context of Apache's Jakarta ORO library: http://www.javaworld.com/javaworld/jw-07-2001/jw-0713-regex.HTML "Regular Expressions and the Java Programming Language," Dana Nourie and Mike McCloskey (Sun Microsystems, August 2002) presents a brief overview of java.util.regex, including five illustrative regex-based applications: http://developer.java.sun.com/developer/technicalArticles/releases/1.4regex/ In "The Java Platform" (onJava.com), an excerpt from Chapter 4 of O'Reilly's Java in a Nutshell, 4th Edition, David Flanagan presents short examples of CharSequence and java.util.regex methods: http://www.onjava.com/pub/a/onjava/excerpt/javanut4_ch04 The Java Tutorial's "Regular Expressions" lesson teaches the basics of Sun's java.util.regex package: http://java.sun.com/docs/books/tutorial/extra/regex/index.HTML Wikipedia defines some regex terminology, presents a brief history of regexes, and explores various regex syntaxes: http://www.wikipedia.org/wiki/Regular_expression Read Jeff's previous Java 101 column: "Tools of the Trade, Part 3" (JavaWorld, January 2003): http://www.javaworld.com/javaworld/jw-01-2003/jw-0103-java101.HTML? Check out past Java 101 articles: http://www.javaworld.com/javaworld/topicalindex/jw-ti-java101.HTML Browse the Core Java section of JavaWorld's Topical Index: http://www.javaworld.com/channel_content/jw-core-index.sHTML Need some Java help? Visit our Java Beginner discussion: http://forums.devworld.com/webx?50@@.ee6b804 Java experts answer your toughest Java questions in JavaWorld's Java Q&A column: http://www.javaworld.com/javaworld/javaqa/javaqa-index.HTML For Tips 'N Tricks, see: http://www.javaworld.com/javaworld/javatips/jw-javatips.index.HTML Sign up for JavaWorld's free weekly Core Java email newsletter: http://www.javaworld.com/subscribe You'll find a wealth of IT-related articles from our sister publications at IDG.net |
最近读者: