字符串处理是许多程序中非常重要的一部分,它们可以用于文本显示,数据表示,查找键和很多目的.在Unix下,用户可以使用正则表达式的强健功能实现

这些目的,从Java1.4起,Java核心API就引入了java.util.regex程序包,它是一种有价值的基础工具,可以用于很多类型的文本处理,如匹配,搜索,提取

和分析结构化内容.

java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。它包括两个类:Pattern和Matcher.
Pattern是一个正则表达式经编译后的表现模式。 在java中,通过适当命名的Pattern类可以容易确定String是否匹配某种模式.模式可以象匹配某个特

定的String那样简单,也可以很复杂,需要采用分组和字符类,如空白,数字,字母或控制符.因为Java字符串基于统一字符编码(Unicode),正则表达式也

适用于国际化的应用程序.

Pattern类的方法简述
方法 说明
static Pettern compile(String regex,int flag) 编译模式,参数regex表示输入的正则表达式,flag表示模式类型(Pattern.CASE_INSENSITIVE 表示

不区分大小写)
Matcher match(CharSequence input) 获取匹配器,input时输入的待处理的字符串
static boolean matches(String regex, CharSequence input) 快速的匹配调用,直接根据输入的模式regex匹配input
String[] split(CharSequence input,int limit) 分隔字符串input,limit参数可以限制分隔的次数


Matcher 一个Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查。首先一个Pattern实例订制了一个所用语法与

PERL的类似的正则表达式经编译后的模式,然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字符串的匹配工作。

Matcher类的方法简述
方法 说明
boolean matches() 对整个输入字符串进行模式匹配.
boolean lookingAt() 从输入字符串的开始处进行模式匹配
boolean find(int start) 从start处开始匹配模式
int groupCount() 返回匹配后的分组数目
String replaceAll(String replacement) 用给定的replacement全部替代匹配的部分
String repalceFirst(String replacement) 用给定的replacement替代第一次匹配的部分
Matcher appendReplacement(StringBuffer sb,String replacement) 根据模式用replacement替换相应内容,并将匹配的结果添加到sb当前位置之后
StringBuffer appendTail(StringBuffer sb) 将输入序列中匹配之后的末尾字串添加到sb当前位置之后.

正则表达式中常见通配符:
对于单字符串比较而言,使用正则表达式没有什么优势.Regex的真正强大之处在于体现在包括字符类和量词(*,+,?)的更复杂的模式上.
字符类包括:
\d 数字
\D 非数字
\w 单字字符(0-9,A-Z,a-z)
\W 非单字字符
\s 空白(空格符,换行符,回车符,制表符)
\S 非空白
[] 由方括号内的一个字符列表创建的自定义字符类
.   匹配任何单个字符
下面的字符将用于控制将一个子模式应用到匹配次数的过程.
? 重复前面的子模式0次到一次
* 重复前面的子模式0次或多次
+ 重复前面的子模式一次到多次


以下是实例部分:

实例一:
正则式是最简单的能准确匹配一个给定String的模式,模式与要匹配的文本是等价的.静态的Pattern.matches方法用于比较一个String是否匹配一个给

定模式.例程如下:
String data="java";
boolean result=Pattern.matches("java",data);

实例二:
String[] dataArr = { "moon", "mon", "moon", "mono" };

    for (String str : dataArr) {
      String patternStr="m(o+)n";

      boolean result = Pattern.matches(patternStr, str);
      if (result) {
        System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
      }
      else{
        System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
      }    
    }

模式是”m(o+)n”,它表示mn中间的o可以重复一次或多次,因此moon,mon,mooon能匹配成功,而mono在n后多了一个o,和模式匹配不上.

注:
+表示一次或多次;?表示0次或一次;*表示0次或多次.

实例三:
String[] dataArr = { "ban", "ben", "bin", "bon" ,"bun","byn","baen"};

    for (String str : dataArr) {
      String patternStr="b[aeiou]n";

      boolean result = Pattern.matches(patternStr, str);
      if (result) {
        System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
      }
      else{
        System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
      }    
    }

注:方括号中只允许的单个字符,模式“b[aeiou]n”指定,只有以b开头,n结尾,中间是a,e,i,o,u中任意一个的才能匹配上,所以数组的前五个可以匹配,

后两个元素无法匹配.

方括号[]表示只有其中指定的字符才能匹配.

实例四:
String[] dataArr = { "been", "bean", "boon", "buin" ,"bynn"};

    for (String str : dataArr) {
      String patternStr="b(ee|ea|oo)n";

      boolean result = Pattern.matches(patternStr, str);
      if (result) {
        System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
      }
      else{
        System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
      }    
    }

如果需要匹配多个字符,那么[]就不能用上了,这里我们可以用()加上|来代替,()表示一组,|表示或的关系,模式b(ee|ea|oo)n就能匹配been,bean,boon

等.
因此前三个能匹配上,而后两个不能.

实例五:
String[] dataArr = { "1", "10", "101", "1010" ,"100+"};

    for (String str : dataArr) {
      String patternStr="\\d+";

      boolean result = Pattern.matches(patternStr, str);
      if (result) {
        System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
      }
      else{
        System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
      }    
    }

注:从前面可以知道,\\d表示的是数字,而+表示一次或多次,所以模式\\d+就表示一位或多位数字.
因此前四个能匹配上,最后一个因为+号是非数字字符而匹配不上.

实例六:
String[] dataArr = { "a100", "b20", "c30", "df10000" ,"gh0t"};

    for (String str : dataArr) {
      String patternStr="\\w+\\d+";

      boolean result = Pattern.matches(patternStr, str);
      if (result) {
        System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
      }
      else{
        System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
      }    
    }

模式\\w+\\d+表示的是以多个单字字符开头,多个数字结尾的字符串,因此前四个能匹配上,最后一个因为数字后还含有单字字符而不能匹配.

实例七:
String str="薪水,职位 姓名;年龄 性别";
    String[] dataArr =str.split("[,\\s;]");
    for (String strTmp : dataArr) {
      System.out.println(strTmp);
    }

String类的split函数支持正则表达式,上例中模式能匹配”,”,单个空格,”;”中的一个,split函数能把它们中任意一个当作分隔符,将一个字符串劈

分成字符串数组.

实例八:
String str="2007年12月11日";
Pattern p = Pattern.compile("[年月日]");
String[] dataArr =p.split(str);
for (String strTmp : dataArr) {
System.out.println(strTmp);
}

Pattern是一个正则表达式经编译后的表现模式 ,它的split方法能有效劈分字符串.
注意其和String.split()使用上的不同.

实例九:
String str="10元 1000人民币 10000元 100000RMB";
str=str.replaceAll("(\\d+)(元|人民币|RMB)", "$1¥");
System.out.println(str);

上例中,模式“(\\d+)(元|人民币|RMB)”按括号分成了两组,第一组\\d+匹配单个或多个数字,第二组匹配元,人民币,RMB中的任意一个,替换部分$1表

示第一个组匹配的部分不变,其余组替换成¥.

替换后的str为¥10 ¥1000 ¥10000 ¥100000

实例十:
Pattern p = Pattern.compile("m(o+)n",Pattern.CASE_INSENSITIVE);

// 用Pattern类的matcher()方法生成一个Matcher对象
Matcher m = p.matcher("moon mooon Mon mooooon Mooon");
StringBuffer sb = new StringBuffer();

// 使用find()方法查找第一个匹配的对象
boolean result = m.find();

// 使用循环找出模式匹配的内容替换之,再将内容加到sb里
while (result) {
m.appendReplacement(sb, "moon");
result = m.find();
}
// 最后调用appendTail()方法将最后一次匹配后的剩余字符串加到sb里;
m.appendTail(sb);

System.out.println("替换后内容是" + sb.toString());

实例十一:
除了用+表示一次或多次,*表示0次或多次,?表示0次或一次外,还可以用{}来指定精确指定出现的次数,X{2,5}表示X最少出现2次,最多出现5次;X{2,}表

示X最少出现2次,多则不限;X{5}表示X只精确的出现5次.
例程:
String[] dataArr = { "google", "gooogle", "gooooogle", "goooooogle","ggle"};

for (String str : dataArr) {
    String patternStr = "g(o{2,5})gle";

    boolean result = Pattern.matches(patternStr, str);
    if (result) {
        System.out.println("字符串" + str + "匹配模式" + patternStr + "成功");
    } else {
        System.out.println("字符串" + str + "匹配模式" + patternStr + "失败");
    }
}

实例十二:
-表示从..到…,如[a-e]等同于[abcde]
String[] dataArr = { "Tan", "Tbn", "Tcn", "Ton","Twn"};

    for (String str : dataArr) {
      String regex = "T[a-c]n";

      boolean result = Pattern.matches(regex, str);
      if (result) {
        System.out.println("字符串" + str + "匹配模式" + regex + "成功");
      } else {
        System.out.println("字符串" + str + "匹配模式" + regex + "失败");
      }
    }
实例十三:不区分大小写匹配.
正则表达式默认都是区分大小写的,使用了Pattern.CASE_INSENSITIVE则不对大小写进行区分.

String patternStr="ab";
    Pattern pattern=Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);

    String[] dataArr = { "ab", "Ab", "AB"};

    for (String str : dataArr) {
      Matcher matcher=pattern.matcher(str);

      if(matcher.find()){
        System.out.println("字符串" + str + "匹配模式" + patternStr + "成功");
      }
    }

实例十四:使用正则表达式劈分字符串.
注意这里要把复杂的模式写在前面,否则简单模式会先匹配上.

String input="职务=GM 薪水=50000 , 姓名=职业经理人 ; 性别=男 年龄=45 ";
    String patternStr="(\\s*,\\s*)|(\\s*;\\s*)|(\\s+)";
    Pattern pattern=Pattern.compile(patternStr);

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

    for (String str : dataArr) {
      System.out.println(str);
    }
实例十五:解析正则表达式中的文字,\\1对应第一个小括号括起来的group1.
String regex="<(\\w+)>(\\w+)</\\1>";
Pattern pattern=Pattern.compile(regex);

String input="<name>Bill</name><salary>50000</salary><title>GM</title>";

Matcher matcher=pattern.matcher(input);

while(matcher.find()){
      System.out.println(matcher.group(2));
}


实例十六:将单词数字混合的字符串的单词部分大写.
    String regex="([a-zA-Z]+[0-9]+)";  
    Pattern pattern=Pattern.compile(regex);

    String input="age45 salary500000 50000 title";

    Matcher matcher=pattern.matcher(input);

    StringBuffer sb=new StringBuffer();

    while(matcher.find()){
      String replacement=matcher.group(1).toUpperCase();
      matcher.appendReplacement(sb, replacement);
    }
    matcher.appendTail(sb);

    System.out.println("替换完的字串为"+sb.toString());


首先说一下java正则表达式的重点概念:
第一、相关类:Pattern、Matcher
第二、典型的调用顺序是
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
在仅使用一次正则表达式时,可以方便地通过此类定义 matches 方法。此方法编译表达式并在单个调用中将输入序列与其匹配。
语句 boolean b = Pattern.matches("a*b", "aaaaab");等效于上面的三个语句,尽管对于重复的匹配而言它效率不高,因为它不允许重用已编译的模式。
此类的实例是不可变的,可供多个并发线程安全使用。Matcher 类的实例用于此目的则不安全。

第三、正则表达式的构造摘要
字符类
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)

说明:
[]表示范围--某一个字符的范围
^表示非
&&表示

预定义字符类
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]
说明:预定义字符类和字符类部分可以互换。如:[0-9] == \d

数量词
X? :X出现一次或一次也没有
X* :X出现零次或多次
X+ :X出现一次或多次
X{n} :X出现恰好 n 次
X{n,} :X出现至少 n 次
X{n,m} :X出现至少 n 次,但是不超过 m 次
例子:a?bc 表示在一个字符串中a出现0次或1次,abc或bc都可以匹配,aabc不可匹配

捕获组和非捕获组

组的表示方法:
捕获组

捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:

1     ((A)(B(C)))
2     \A
3     (B(C))
4     (C)

组零始终代表整个表达式

之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器检索。


Back 引用 是说在后面的表达式中我们可以使用组的编号来引用前面的表达式所捕获到的文本序列(是文本不是正则)。


例如 ([" ']).* \1   其中使用了分组,\1就是对引号这个分组的引用,它匹配包含在两个引号或者两个单引号中的所有字符串,如,"abc" 或 " ' " 或 ' " ' ,但是请注意,它并不会对" a'或者 'a"匹配。原因上面已经说明,Back引用只是引用文本而不是表达式。


非捕获组

      以 (?) 开头的组是纯的非捕获 组,它不捕获文本,也不针对组合计进行计数。就是说,如果小括号中以?号开头,那么这个分组就不会捕获文本,当然也不会有组的编号,因此也不存在Back 引用。

在Java中,支持的非捕获组,有如下几种:

(?=X)     X,通过零宽度的正 lookahead 即左侧匹配
(?!X)     X,通过零宽度的负 lookahead 即左侧匹配
(?<=X)     X,通过零宽度的正 lookbehind 即右侧匹配
(?<!X)     X,通过零宽度的负 lookbehind 即右侧匹配


这四个非捕获组用于匹配表达式X,但是不包含表达式的文本。

(?=X )
零宽度正先行断言。仅当子表达式 X 在 此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。
(?!X)
零宽度负先行断言。仅当子表达式 X 不在 此位置的右侧匹配时才继续匹配。例如,例如,\w+(?!\d) 与后不跟数字的单词匹配,而不与该数字匹配。
(?<=X)
零宽度正后发断言。仅当子表达式 X 在 此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。
(?<!X)
零宽度负后发断言。仅当子表达式 X 不在此位置的左侧匹配时才继续匹配。例如,(?<!19)99 与不跟在 19 后面的 99 的实例匹配

说明:
非捕获组中四个表达式的区别:
(?=X ) 和(?!X)用于右侧匹配
(?<=X)和(?<!X)用于左侧匹配


举例:

上面都是理论性的介绍,这里就使用一些例子来说明一下问题:

   1、测试匹配性   (abc)+def(?<!4)56(?=9) 这里的含义就是匹配 以一个或多个abc开头后跟def的文本,而且后面的文本56前面不能是4,后面必须是9组成。因此,可以匹配如下文本 abcdef5569 ,与abcdef4569不匹配。


2 、提取字符串   提取 da12bka3434bdca4343bdca234bm   提取包含在字符a和b之间的数字,但是这个a之前的字符不能是c,b后面的字符必须是d才能提取。
        例如这里就只有3434这个数字满足要求。那么我们怎么提取呢?

       首先我们写出提取这个字符串的表达式: (?<!c)a(\d+)bd 这里就只有一个捕获组(\d+)

JAVA代码片段如下:
Pattern p = Pattern.compile("(?<!c)a(\\d+)bd");
Matcher m = p.matcher("da12bca3434bdca4343bdca234bm");
while(m.find()){
   System.out.println(m.group(1)); //我们只要捕获组1的数字即可。结果 3434
   System.out.println(m.group(0)); // 0组是整个表达式,看这里,并没有提炼出(?<!c)的字符 。结果 a3434bd
}

可以看到,非捕获组,最后是不会返回结果的,因为它本身并不捕获文本。

/**
*
*/
package cn.com.kn.test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* 功能说明: 2009-1-13 上午10:27:44
*
* @author gmw
*
*/

public class PatternTest {

public void testParttern(){
                  //表达式的功能:验证必须为数字(整数或小数)
   String pattern = "[0-9]+(.[0-9]+)?";
   //对()的用法总结:将()中的表达式作为一个整体进行处理,必须满足他的整体结构才可以。
   //(.[0-9]+)? :表示()中的整体出现一次或一次也不出现
   Pattern p = Pattern.compile(pattern);
   Matcher m = p.matcher("2");
   boolean b = m.matches();
   if(b){
    System.out.println("istrue:"+b);
   }

}

public static void main(String[] args) {
   PatternTest pt = new PatternTest();
//   pt.testFormat("2");
   pt.testParttern();
    }
}