学点Java正则表达式

正则表达式用来指定字符串模式。当你需要定位匹配某种模式的字符串时就可以使用正则表达式。例如,我们下面的一个例程就是在一个HTML文件中通过查找字符串模式<a href="...">来定位所有的超链接。

    当然,为了指定一种模式,使用...这种记号是不够精确的。你需要精确地指定什么样的字符排列是一个合法的匹配。当描述某种模式时,你需要使用一种特殊的语法。

    这里有一个简单例子。正则表达式
[Jj]ava.+
匹配下列形式的任何字符串:

  • 首字母是J或j
  • 后续的三个字母是ava
  • 字符串的剩余部分由一个或多个任意字符组成


    例如,字符串“javaness”匹配这个特殊的正则表达式,但是字符串“Core Java”却不匹配。

    如你所见,你需要了解一点语法来理解正则表达式的含意。幸运的是对于大多数的用途,使用少量的简单构造(straightforward constructs)就已足够。

  • 字符类是可选自符的集合,用‘[’封装,比如[Jj],[0-9],[A-Za-z]或[^0-9]。这里的-表示范围(Unicode落在两个边界之间的所有字符),^表示求补(指定字符外的所有字符)。
  • 有许多预定以的字符类,像/d(数字)或/p{Sc}(Unicode货币符号),见表12-8和12-9。
  • 大多数字符与它们自身匹配,像上例中的ava字符。
  • 符号.匹配任何字符(可能行终止符(line terminators)除外,这依赖于标识设置(flag settings))
  • /用作转义符,比如/.匹配一个句点,//匹配一个反斜杠。
  •  ^和$分别匹配行头和行尾
  • 如果X和Y都是正则表达式,则XY表示“X的匹配后面跟着Y的匹配”。X|Y表示“任何X或Y的匹配”
  • 可以将量词(quantifier)用到表达式中,X+ 表示X重复1次或多次,X* 表示X重复0次或多次,X? 表示X重复0次或1次
  •  默认地,一个量词总是与使总体成功匹配的最长的可能重复匹配。可以加上后缀?(称为reluctant或stingy 匹配,用以匹配最小的重复数),和+(称为possessive或贪婪匹配,用以即使在总体匹配失败的情况下也匹配最大的重复数)来更改这种属性。


例如,字符串cab匹配[a-z]*ab,但不匹配[a-z]*+ab。第一种情况下,[a-z]*只匹配字符c,因此字符ab正好与模式的剩余部分匹配。但是贪婪版本[a-z]*+就与字符cab匹配,模式的剩余部分ab就匹配失败(,这样总体也就匹配失败)。
  • 可以使用分组来定义子表达式。将分组封装在()中,如([+-]?)([0-9]+)。然后你可以让模式匹配符(the pattern matcher)返回每个分组的匹配,或者使用/n来回引分组(refer back to a group with /n),其中n是组号(以/1起始)


    这里有一个稍微有点复杂却又很有用的正则表达式--它用来描述十进制和十六进制的整数。
[+-]?[0-9]+|0[Xx][0-9A-Fa-f]+

    不幸的是,在使用正则表达式的各种程序和库之间,它的语法还没有完全标准化。对基本的构造上已达成了共识,但在细节方面有许多令人“抓狂”的区别(many maddening differences)。Java的正则表达式类使用了与Perl语言类似的语法,但也不尽相同。表12-8显示了Java语法的所有正则表达式构造。要了解更多关于正则表达式的信息,请参考Pattern类的API文档,或者Jeffrey E. F. Friedl的著作《Mastering Regular Expressions》(O'Reilly and Associates, 1997)(刚去第二书店查了一下,东南大学出版社已经引入了其第二版,影印)

表12-8 正则表达式语法


语法                                                          解释


字符
c                                                            字符c
/unnnn, /xnn, /0n, /0nn, /0nnn          带有十六或八进制值的代码单元

/0n                                           八进制0n代表的字符(0<=n<=7)
/0nn                                         八进制0nn代表的字符(0<=n<=7)
/0mnn                                     八进制0mnn代表的字符(0<=m<=3,0<=n<=7)
/xnn                                         十六进制 0xnn所代表的字符
/uhhhh                                    十六进制 0xhhhh所代表的字符

/t, /n, /r, /f, /a, /e                                    控制字符,依次是制表符,换行符,回车符,换页符,报警符和转义符
/cc                                                         控制字符中出现的相应字符c


字符类
[C1C2. . .]                       C1、C2……中的任何字符。Ci可以是字符,字符范围(C1-C2)或者字符类。
[^. . .]                                字符类的补集
[ . . . && . . .]                    两个字符类的交集


预定义字符类
.                                        除行终止符外的任何字符(如果DOTALL标志置位,则表示任何字符)
/d                                      数字[0-9]
/D                                    非数字[^0-9]
/s                                     空白字符[/t/n/r/f/x0B]
/S                                     非空白字符
/w                                    单词字符[a-zA-Z0-9_]
/W                                   非单词字符
/p{name}                        一个指定的字符类,见表12-9
/P{name}                       指定字符类的补集


边界匹配符
^ $                                   输入的开头和结尾(在多行模式(multiline mode)下是行的开头和结尾)
/b                                    单词边界
/B                                    非单词边界
/A                                     输入的开头
/z                                     输入的结尾
/Z                                    除最后行终止符之外的输入结尾
/G                                   上个匹配的结尾


量词
X?                                    可选的X(即X可能出现,也可能不出现)
X*                                    X,可以重复0次或多次
X+                                    X,可以重复1次或多次
X{n} X{n,} X{n,m}          X重复n次,至少重复n次,重复n到m次


量词后缀
?                                   设默认(贪婪)匹配为reluctant匹配
+                                   设默认(贪婪)匹配为possessive匹配


集合操作
XY                                  X的匹配后面跟着Y的匹配
X|Y                                 X或Y的匹配


分组
(X)                                匹配X并且在一个自动计数的分组中捕获它
/n                                  与第n个分组的匹配


转义
/c                                   字符c(必须不是字母)
/Q.../E                            逐字地引用...
(?...)                       特殊构造,看Pattern类的API



    正则表达式的最简单使用是测试一个特殊的字符串是否与之匹配。这里有一个Java写的测试程序。首先从表示正则表达式的字符串构造一个Pattern对象。然后从该模式获得一个Matcher对象,并且调用它的matches()方法:

Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) . . .


    表12.9 预定义的字符类名(Predefined Character Class Names)


Lower                         小写的ASII字符[a-z]
Upper                         大写的ASCII字符[A-Z]
Alpha                          ASCII字母[A-Za-z]
Digit                            ASCII 数字 [0-9]
Alnum                         ASCII 字母或数字[A-Za-z0-9]
Xdigit                         十六进制数字[0-9A-Fa-f]
Print or Graph          可打印的ASCII字符[/x21-/x7E]
Punct                         非字母或数字ASCII [/p{Print}&&/P{Alnum}]
ASCII                         所有ASCII字符 [/x00-/x7F]
Cntrl                          ASCII控制字符[/x00-/x1F]
Blank                         空格符或制表符[ /t]
Space                        空白符 [ /t/n/r/f/0x0B]
javaLowerCase       取决于Character.isLowerCase()的小写字符
javaUpperCase      取决于Character.isUpperCase()的大写字符
javaWhitespace     取决于Character.isWhitespace()的空白符
javaMirrored            取决于Character.isMirrored()的Mirrored(?)
InBlock                      这里的Block是unicode字符的块名,用空格隔开,比如BasicLatin 或 Mongolian。块名列表                                  参考http://www.unicode.org
Category 或InCategory     这里的Category是Unicode字符的种类名,比如L(字母)或者Sc(货币符号)。种类                                        名列表参考http://www.unicode.org 



    matcher的输入可以是实现CharSequence接口的任何类对象,像String,StringBuilder或CharBuffer。

    当编译模式时,可以设置一个或多个标志,例如

Pattern pattern = Pattern.compile(patternString,
Pattern.CASE_INSENSITIVE + Pattern.UNICODE_CASE);


下面六个标志都是支持的:

CASE_INSENSITIVE:匹配字符时与大小写无关,该标志默认只考虑US ASCII字符。
UNICODE_CASE:当与CASE_INSENSITIVE结合时,使用Unicode字母匹配
MULTILINE:^和$匹配一行的开始和结尾,而不是整个输入
UNIX_LINES: 当在多行模式下匹配^和$时,只将'/n'看作行终止符
DOTALL: 当使用此标志时,.符号匹配包括行终止符在内的所有字符
CANON_EQ: 考虑Unicode字符的规范等价

     如果正则表达式包含分组,Matcher对象能够揭示分组边界。方法

int start(int groupIndex)
int end(int groupIndex)

返回某个特殊分组的起始索引和结尾后索引(past-the-end index )。
通过调用String group(int groupIndex),你可以简单地得到匹配的字符串。
第0个分组代表所有的分组,第一个实际分组的索引是1。调用groupCount来获得总的分组数。

     使用开放圆括号来安排嵌套分组。例如,给定模式((1?[0-9]):([0-5][0-9]))[ap]m,并且输入11:59am,Matcher对象报告下列分组
((1?[0-9]):([0-5][0-9]))[ap]m
并输入
11:59am
matcher报告下列分组


分组索引  起始  结束  字符串


0              0          7      11;59am
1              0          5      11:59
2              0          2      11
3              3          5      59


 
例12-9提示输入一个模式和一个欲匹配的字符串。它将输出输入的字符串是否匹配模式。如果输入匹配包含分组的模式,程序将会使用圆括号来打印分组边界,如((11):(59))am

Example 12-9. RegexTest.java
 1. import java.util.*;
 2. import java.util.regex.*;
 3.
 4. /**
 5.    This program tests regular expression matching.
 6.    Enter a pattern and strings to match, or hit Cancel
 7.    to exit. If the pattern contains groups, the group
 8.    boundaries are displayed in the match.
 9. */
10. public class RegExTest
11. {
12.   public static void main(String[] args)
13.   {
14.      Scanner in = new Scanner(System.in);
15.      System.out.println("Enter pattern: ");
16.      String patternString = in.nextLine();
17.
18.      Pattern pattern = null;
19.      try
20.      {
21.         pattern = Pattern.compile(patternString);
22.      }
23.      catch (PatternSyntaxException e)
24.      {
25.         System.out.println("Pattern syntax error");
26.         System.exit(1);
27.      }
28.
29.      while (true)
30.      {
31.         System.out.println("Enter string to match: ");
32.         String input = in.nextLine();
33.         if (input == null || input.equals("")) return;
34.         Matcher matcher = pattern.matcher(input);
35.         if (matcher.matches())
36.         {
37.            System.out.println("Match");
38.            int g = matcher.groupCount();
39.            if (g > 0)
40.            {
41.               for (int i = 0; i < input.length(); i++)
42.               {
43.                  for (int j = 1; j <= g; j++)
44.                     if (i == matcher.start(j))
45.                        System.out.print('(');
46.                  System.out.print(input.charAt(i));
47.                  for (int j = 1; j <= g; j++)
48.                     if (i + 1 == matcher.end(j))
49.                        System.out.print(')');
50.               }
51.               System.out.println();
52.            }
53.         }
54.         else
55.            System.out.println("No match");
56.      }
57.   }
58. }

     通常地,你不希望匹配整个输入到某个正则表达式,而是希望在输入中找出一个或多个匹配的子字符串。使用Matcher类的find方法来寻找下一个匹配。如果它返回True,再使用start和end方法找出匹配的范围。

while (matcher.find())
{
   int start = matcher.start();
   int end = matcher.end();
   String match = input.substring(start, end);
   . . .
}


例12-10用到了这种机制。它在一个网页中定位所有的超文本引用并打印它们。为运行程序,在命令行提供一个URL,比如
java HrefMatch http://www.horstmann.com

Example 12-10. HrefMatch.java
 1. import java.io.*;
 2. import java.net.*;
 3. import java.util.regex.*;
 4.
 5. /**
 6.    This program displays all URLs in a web page by
 7.    matching a regular expression that describes the
 8.    <a href=...> HTML tag. Start the program as
 9.    java HrefMatch URL
10. */
11. public class HrefMatch
12. {
13.    public static void main(String[] args)
14.    {
15.       try
16.       {
17.          // get URL string from command line or use default
18.          String urlString;
19.          if (args.length > 0) urlString = args[0];
20.          else urlString = "http://java.sun.com";
21.
22.          // open reader for URL
23.          InputStreamReader in = new InputStreamReader(new URL(urlString).openStream());
24.
25.          // read contents into string buffer
26.          StringBuilder input = new StringBuilder();
27.          int ch;
28.          while ((ch = in.read()) != -1) input.append((char) ch);
29.
30.          // search for all occurrences of pattern
31.          String patternString = "<a//s+href//s*=//s*(/"[^/"]*/"|[^//s>])//s*>";
32.          Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
33.          Matcher matcher = pattern.matcher(input);
34.
35.          while (matcher.find())
36.          {
37.             int start = matcher.start();
38.             int end = matcher.end();
39.             String match = input.substring(start, end);
40.             System.out.println(match);
41.          }
42.       }
43.       catch (IOException e)
44.       {
45.          e.printStackTrace();
46.       }
47.       catch (PatternSyntaxException e)
48.       {
49.          e.printStackTrace();
50.       }
51.    }
52. }

    Matcher类的replaceAll方法用一个替换字符串代替出现的所有正则表达式的匹配。比如,下列指令用#替换所有数字序列

Pattern pattern = Pattern.compile("[0-9]+");
Matcher matcher = pattern.matcher(input);
String output = matcher.replaceAll("#");

    替换字符串可以包含模式中的分组引用:$n被第n个分组替换。替换文本中出现$时,使用/$来包含它。
replaceFirst方法只替换模式的第一次出现。

    最后讲一点,Pattern类有一个split方法,它类似于字符串tokenizer。它使用正则表达式匹配作边界,将输入分离成字符串数组。比如,下面的指令将输入分离成记号(token),

Pattern pattern = Pattern.compile("//s*//p{Punct}//s*");
String[] tokens = pattern.split(input);




java.util.regex.Pattern 1.4


方法
static Pattern compile(String expression)
static Pattern compile(String expression, int flags)
编译正则表达式字符串到pattern对象用以匹配的快速处理
参数:
 expression 正则表达式
 flags            下列标志中的一个或多个 CASE_INSENSITIVE, UNICODE_CASE, MULTILINE, UNIX_LINES, DOTALL, and CANON_EQ
 
Matcher matcher(CharSequence input)
返回一个matcher对象,它可以用来在一个输入中定位模式匹配

String[] split(CharSequence input)
String[] split(CharSequence input, int limit)
将输入字符串分离成记号,并由pattern来指定分隔符的形式。返回记号数组。分隔符并不是记号的一部分。
参数:
input 分离成记号的字符串
limit 生成的最大字符串数。


 类


java.util.regex.Matcher 1.4


方法


boolean matches()
返回输入是否与模式匹配

boolean lookingAt()
如果输入的起始匹配模式则返回True

boolean find()
boolean find(int start)
尝试查找下一个匹配,并在找到匹配时返回True
参数:
 start  开始搜索的索引
 
int start()
int end()
返回当前匹配的起始位置和结尾后位置

String group()
返回当前匹配

int groupCount()
返回输入模式中的分组数

int start(int groupIndex)
int end(int groupIndex)
返回一个给定分组当前匹配中的起始位置和结尾后位置
参数:
 groupIndex分组索引(从1开始),0表示整个匹配

String group(int groupIndex)
返回匹配一个给定分组的字符串
参数:
 groupIndex
 分组索引(从1开始),0表示整个匹配

String replaceAll(String replacement)
String replaceFirst(String replacement)
返回从matcher输入得到的字符串,但已经用替换表达式替换所有或第一个匹配
参数:
 replacement 替换字符串

Matcher reset()
Matcher reset(CharSequence input)
复位mather状态。

阅读更多
个人分类: J2SE 文章
想对作者说点什么? 我来说一句

批处理教程 批处理教程

2011年05月20日 199KB 下载

JAAV正则表达式

2017年09月05日 80KB 下载

Java正则表达式Java正则表达式

2010年09月19日 4KB 下载

Java正则表达式

2011年10月19日 49KB 下载

java正则表达式PPT

2010年07月20日 967KB 下载

Java正则表达式 Java 正则表达式

2009年12月02日 62KB 下载

java正则表达式大全。。

2011年04月06日 5KB 下载

没有更多推荐了,返回首页

不良信息举报

学点Java正则表达式

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭