有两种使用方式,第一种,匹配两个字符串是不是相等;第二种,找出某个字符串在另一个字符串中的位置。
不管哪种方式,构造正则表达式是非常关键的步骤。正则表达式书写方式比较怪异,不过,真正理解后会发现非常灵活。
看下面这个例子:
[Jj]ava+
[]内定义的是一个字符类,表示当前这个字符位置可能出现的字符的集合,如果这个位置的字符在这个集合内,就算是匹配了。所以以上字符串的第一个字符如果是“J”或者“j”都可以。
由上可知,[]里的内容非常重要,下面就讨论一下[]里内容的写法。例如:[Jj]、[0-9]、[A-Za-z]或[^0-9]。“-”表示一个范围(所有的Unicode值在两个边界之间的所有字符)。而^表示“补集”。
当然,还有很多预先定好的集合,比如/d表示数字,/w表示“A-Za-z0-9_”(数字、字母、下划线)。“.”符号默认表示除了行结束符外的任何字符(如果设置了DOTALL标志,则表示任何字符)。
没有转义的字符,都是和自己匹配的,例如:[abcd]。
上面只是定义了一个字符的范围,如果有很多有同样范围的字符,可以使用量词表示。量词有四种形式:X+(表示匹配一个或多个字符)、X*(表示匹配0个或多个字符)、X?(表示匹配0个或1个字符)、X{n} X{n,} X{n,m}(n个X,至少n个X,n和m之间个X)。
例如:“[a-z]+ab”可以匹配诸如cab、ccab、cdsadfsaab,但是不能匹配ccAab(A不属于a-z)、ab(至少得能匹配一个),而“[a-z]*ab”则除了上面那些可以匹配外,还可以匹配ab。
下面是一个复杂的例子,匹配一个十进制数或者十六进制数。
[+-]?[0-9]+|0[Xx][0-9A-Fa-f]+
附表:正则表达式的语法
中文Java核心卷7版1册653页
表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
表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.orgHYPERLINK "http://www.unicode.org%a0/"
一个检测E-mail地址是否合法的例子:
import java.util.Scanner;
import java.util.regex.*;
public class RegexExercise1 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Pattern a=Pattern.compile("[a-z]+ab");
Matcher m=a.matcher("ab");
System.out.println(m.matches()?"匹配":"不匹配");
String email;
Scanner in=new Scanner(System.in);
System.out.println("请输入邮件地址:");
email=in.nextLine();
String patternString=new String("[//w//.-]+@[//w//.-]+");//“/”在字符串中需要用“//”转义
//patternString="//w+@//w+//.[a-z|A-Z]{2,4}(//.[a-z|A-Z]{2})?";//W3C标准
Pattern pattern=null;
//检验正则表达式是否合法
try
{
pattern=Pattern.compile(patternString);
}
catch(PatternSyntaxException e)
{
System.out.println("错误的正则表达式!");
System.exit(1);
}
Matcher matcher=pattern.matcher(email);
if(matcher.matches())
{
System.out.println("地址合法");
}
else
{
System.out.println("地址非法");
}
}
}
matcher的find()方法实现匹配字符串,如果find()返回true,则可以访问start和end属性,指示字符串的位置。
matcher的appendReplacement实现替换匹配到的字符串。