定义
正则表达式是用来处理字符串的一把利器,它是一个专门匹配n个字符串的字符串模板,本质是查找和替换。许多语言,包括Perl、PHP、Python、JavaScript和JScript,都支持用正则表达式处理文本,一些文本编辑器用正则表达式实现高级“搜索-替换”功能。那么Java又怎样呢?在Java中存在一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包它就是java.util.regex。而在该包中包含是Pattern、Matcher这两个工具类。
为什么要用正则表达式?
正则表达式定义了字符串的模式。
正则表达式可以用来搜索、编辑或处理文本。
正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
一、Pattern和Matcher
Pattern类用于创建一个正则表达式(匹配模式),它的构造方法是私有的,不可以直接创建,但可以通过Pattern.complie(String regex)简单工厂方法创建一个正则表达式.Java代码示例:
Pattern p=Pattern.compile("\\w+");
p.pattern();//返回 \w+
pattern() 返回正则表达式的字符串形式,其实就是返回Pattern.complile(String regex)的regex参数
1.Pattern.split(CharSequence input)
Pattern有一个split(CharSequence input)方法,用于分隔字符串,并返回一个String[],其中String.split(String regex)就是通过Pattern.split(CharSequence input)来实现的.
Java代码示例:
Pattern p=Pattern.compile("\\d+");
String[] str=p.split("AAA456456VVV0532214DDD");
// 结果:str[0]=" AAA " str[1]=" VVV " str[2]=" DDD
2.Pattern.matcher(String regex,CharSequence input)
该方法是一个静态方法,用于快速匹配字符串,该方法适合用于只匹配一次,且匹配全部字符串. Java代码示例:
Pattern.matches("[a-z]{2}+","AA");//返回true
Pattern.matches("[a-z]{2}","A2");//返回false,需要匹配到所有字符串才能返回true
3.Pattern.matcher(CharSequence input)
Pattern.matcher(CharSequence input);//返回一个Matcher对象.
Matcher类的构造方法也是私有的,不能随意创建,只能通过Pattern.matcher(CharSequence input)方法得到该类的实例.
Pattern类只能做一些简单的匹配操作,要想得到更强更便捷的正则匹配操作,那就需要将Pattern与Matcher一起合作.Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持.
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.pattern();//返回p 也就是返回该Matcher对象是由哪个Pattern对象的创建的
4.Matcher类介绍
Matcher类提供三个匹配操作方法它们分别是Matcher.matches() / Matcher.lookingAt() / Matcher.find(),三个方法均返回boolean类型,当匹配到时返回true,没匹配到则返回false。matches()对整个字符串进行匹配,只有整个字符串都匹配了才返回true
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.matches();//返回false,因为bb不能被\d+匹配,导致整个字符串匹配未成功.
Matcher m2=p.matcher("2223");
m2.matches();//返回true,因为\d+匹配到了整个字符串
我们现在回头看一下Pattern.matcher(String regex,CharSequence input),它与下面这段代码等价
Pattern.compile(regex).matcher(input).matches() ;
lookingAt()对前面的字符串进行匹配,只有匹配到的字符串在最前面才返回true,Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.lookingAt();//返回true,因为\d+匹配到了前面的22
Matcher m2=p.matcher("aa2223");
m2.lookingAt();//返回false,因为\d+不能匹配前面的aa
find()对字符串进行匹配,匹配到的字符串可以在任何位置
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.find();//返回true
Matcher m4=p.matcher("aabb");
m4.find();//返回false
5.Mathcer类拓展
当使用matches(),lookingAt(),find()执行匹配操作后,就可以利用以上三个方法得到更详细的信息.
start();//返回匹配到的子字符串在字符串中的索引位置.
end();//返回匹配到的子字符串的最后一个字符在字符串中的索引位置.
group();//返回匹配到的子字符串
Matcher类同时提供了四个将匹配子串替换成指定字符串的方法:
replaceAll() ;
replaceFirst() ;
appendReplacement() ;
appendTail()
replaceAll()与replaceFirst()的用法都比较简单,我们主要重点了解一下appendReplacement()和appendTail()方法。
appendReplacement(StringBuffer sb, String replacement)
将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里,而appendTail(StringBuffer sb)
方法则将最后一次匹配工作后剩余的字符串添加到一个StringBuffer对象里。例如,有字符串fatcatfatcatfat,假设既有正则表达式模式为”cat”,第一次匹配后调用appendReplacement(sb,”dog”),那么这时StringBuffer
sb的内容为fatdog,也就是fatcat中的cat被替换为dog并且与匹配子串前的内容加到sb里,而第二次匹配后调用appendReplacement(sb,”dog”),那么sb的内容就变为fatdogfatdog,如果最后再调用一次appendTail(sb),那么sb最终的内容将是fatdogfatdogfat。
二、正则表达式规则
a.字符类
[abc] a, b, or c (简单类)
[^abc] 除了a、b或c之外的任意 字符(求反)
[a-zA-Z] a到z或A到Z ,包含(范围)
[a-z-[bc]] a到z,除了b和c : [ad-z](减去)
[a-z-[m-p]] a到z,除了m到 p: [a-lq-z]
[a-z-[^def]] d, e, 或 f
备注:
方括号的正则表达式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”,只能匹配单个字符。
圆括号,因为方括号只允许匹配单个字符;故匹配多个字符时使用圆括号“()”。比如使用“t(a|e|i|o|oo)n”正则表达式,就必须用圆括号。
b.预定义的字符类
. 任意字符(也许能与行终止符匹配,也许不能) 备注:句点符号代表任意一个字符。比如:表达式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,还匹配“t#n”、“tpn”甚至“t n”。
\d 数字: [0-9]
\D 非数字: [^0-9]
\s 空格符: [ \t\n\x0B\f\r]
\S 非空格符: [^\s]
\w 单词字符: [a-zA-Z_0-9]
\W 非单词字符: [^\w]
c.表达次数的符号
符号 次数
0次或者多次
1次或者多次
? 0次或者1次
{n} 恰好n次
{n,m} 从n次到m次
三、实例演示
a.字符串操作
/*
* 获取
*/
public static void functionDemo_4() {
String str = "da jia hao,ming tian bu fang jia!";
String regex = "\\b[a-z]{3}\\b";
//1,将正则封装成对象。
Pattern p = Pattern.compile(regex);
//2, 通过正则对象获取匹配器对象。
Matcher m = p.matcher(str);
//使用Matcher对象的方法对字符串进行操作。
//既然要获取三个字母组成的单词
//查找。 find();
System.out.println(str);
while(m.find()){
System.out.println(m.group());//获取匹配的子序列
System.out.println(m.start()+":"+m.end());
}
}
/*
* 替换
*/
public static void functionDemo_3() {
String str = "zhangsanttttxiaoqiangmmmmmmzhaoliu";
str = str.replaceAll("(.)\\1+", "$1");
System.out.println(str);
String tel = "15800001111";//158****1111;
tel = tel.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
System.out.println(tel);
}
/*
* 切割。
* 组:((A)(B(C)))
*/
public static void functionDemo_2(){
String str = "zhangsanttttxiaoqiangmmmmmmzhaoliu";
String[] names = str.split("(.)\\1+");//str.split("\\.");
for(String name : names){
System.out.println(name);
}
}
/*
* 演示匹配。
*/
public static void functionDemo_1(){
//匹配手机号码是否正确。
String tel = "15800001111";
String regex = "1[358]\\d{9}";
boolean b = tel.matches(regex);
System.out.println(tel+":"+b);
}
b.实例操作
//对邮件地址校验。
public static void test_3() {
String mail = "abc1@sina.com.cn";
String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]{1,3})+";
regex = "\\w+@\\w+(\\.\\w+)+";//1@1.1
boolean b = mail.matches(regex);
System.out.println(mail+":"+b);
}
public static void test_1(){
String str = "我我...我我...我我我要...要要要要...要要要要..学学学学学...学学编编...编编编编..编..程程...程程...程程程";
//1,将字符串中.去掉。 用替换。
str = str.replaceAll("\\.+", "");
System.out.println(str);
//2,替换叠词。
str = str.replaceAll("(.)\\1+", "$1");
System.out.println(str);
}
/*
* ip地址排序。
* 192.168.10.34 127.0.0.1 3.3.3.3 105.70.11.55
*/
public static void test_2(){
String ip_str = "192.168.10.34 127.0.0.1 3.3.3.3 105.70.11.55";
//1,为了让ip可以按照字符串顺序比较,只要让ip的每一段的位数相同。所以,补零,按照每一位所需做多0进行补充。每一段都加两个0.
ip_str = ip_str.replaceAll("(\\d+)", "00$1");
System.out.println(ip_str);
//然后每一段保留数字3位。
ip_str = ip_str.replaceAll("0*(\\d{3})", "$1");
System.out.println(ip_str);
//1,将ip地址切出。
String[] ips = ip_str.split(" +");
TreeSet ts = new TreeSet();
for(String ip : ips){
ts.add(ip);
}
for(String ip : ts){
System.out.println(ip.replaceAll("0*(\\d+)", "$1"));
}
}
四、总结
正则表达式是操作字符串的有效手段,但是在方便我们开发的同时,我们必须意识到正则表达式存在一定的缺陷那就是如果在程序中过多使用正则表达式会造成程序的阅读性急速下降。
常用的正则表达式:
五、一些常用的正则表达式
(1) “^\d+$” //非负整数(正整数 + 0)
(2) “^[0-9][1-9][0-9]$” //正整数
(3) “^((-\d+)|(0+))$” //非正整数(负整数 + 0)
(4) “^-[0-9][1-9][0-9]$” //负整数
(5) “^-?\d+$” //整数
(6) “^\d+(.\d+)?$” //非负浮点数(正浮点数 + 0)
(7) “^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$” //正浮点数
(8) “^((-\d+(.\d+)?)|(0+(.0+)?))$” //非正浮点数(负浮点数 + 0)
(9) “^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$” //负浮点数
(10) “^(-?\d+)(.\d+)?$” //浮点数
(11) “^[A-Za-z]+$” //由26个英文字母组成的字符串
(12) “^[A-Z]+$” //由26个英文字母的大写组成的字符串
(13) “^[a-z]+$” //由26个英文字母的小写组成的字符串
(14) “^[A-Za-z0-9]+$” //由数字和26个英文字母组成的字符串
(15) “^\w+$” //由数字、26个英文字母或者下划线组成的字符串
(16) “^[\w-]+(.[\w-]+)*@[\w-]+(.[\w-]+)+$” //email地址
(17) “^[a-zA-z]+://(\w+(-\w+))(.(\w+(-\w+)))(\?\S)?$” //url
(18) /^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-((0-2)|(3[0|1]))$/ // 年-月-日
(19) /^((0([1-9]{1}))|(1[1|2]))/((0-2)|(3[0|1]))/(d{2}|d{4})$/ // 月/日/年
(20) “^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$” //Emil
(21) /^((+?[0-9]{2,4}-[0-9]{3,4}-)|([0-9]{3,4}-))?([0-9]{7,8})(-[0-9]+)?$/ //电话号码
(22) “^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$” //IP地址
(23) 匹配中文字符的正则表达式: [\u4e00-\u9fa5]
(24) 匹配双字节字符(包括汉字在内):[^\x00-\xff]
(25) 匹配空行的正则表达式:\n[\s| ]*\r
(26) 匹配HTML标记的正则表达式:/<(.)>.<\/\1>|<(.*) \/>/
(27) 匹配首尾空格的正则表达式:(^\s*)|(\s*$)
(28) 匹配Email地址的正则表达式:\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*
(29) 匹配网址URL的正则表达式:^[a-zA-z]+://(\w+(-\w+))(\.(\w+(-\w+)))(\?\S)?$
(30) 匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
(31) 匹配国内电话号码:(\d{3}-|\d{4}-)?(\d{8}|\d{7})?
(32) 匹配腾讯QQ号:^[1-9][1-9][0-9]$
(33) 元字符及其在正则表达式上下文中的行为:
(34) \ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。
(35) ^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的Multiline 属性,^ 也匹配 ’\n’ 或 ’\r’ 之后的位置。
(36) 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性, 匹 配 输 入 字 符 串 的 结 束 位 置 。 如 果 设 置 了 R e g E x p 对 象 的 M u l t i l i n e 属 性 , 也匹配 ’\n’ 或 ’\r’ 之前的位置。
(37) * 匹配前面的子表达式零次或多次。
(38) + 匹配前面的子表达式一次或多次。+ 等价于 {1,}。
(39) ? 匹配前面的子表达式零次或一次。? 等价于 {0,1}。
(40) {n} n 是一个非负整数,匹配确定的n 次。
(41) {n,} n 是一个非负整数,至少匹配n 次。
(42) {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。在逗号和两个数之间不能有空格。
(43) ? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。
(44) . 匹配除 “\n” 之外的任何单个字符。要匹配包括 ’\n’ 在内的任何字符,请使用象 ’[.\n]’ 的模式。
(45) (pattern) 匹配pattern 并获取这一匹配。
(46) (?:pattern) 匹配pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。
(47) (?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
(48) (?!pattern) 负向预查,与(?=pattern)作用相反
(49) x|y 匹配 x 或 y。
(50) [xyz] 字符集合。
(51) [^xyz] 负值字符集合。
(52) [a-z] 字符范围,匹配指定范围内的任意字符。
(53) [^a-z] 负值字符范围,匹配任何不在指定范围内的任意字符。
(54) \b 匹配一个单词边界,也就是指单词和空格间的位置。
(55) \B 匹配非单词边界。
(56) \cx 匹配由x指明的控制字符。
(57) \d 匹配一个数字字符。等价于 [0-9]。
(58) \D 匹配一个非数字字符。等价于 [^0-9]。
(59) \f 匹配一个换页符。等价于 \x0c 和 \cL。
(60) \n 匹配一个换行符。等价于 \x0a 和 \cJ。
(61) \r 匹配一个回车符。等价于 \x0d 和 \cM。
(62) \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
(63) \S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
(64) \t 匹配一个制表符。等价于 \x09 和 \cI。
(65) \v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
(66) \w 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。
(67) \W 匹配任何非单词字符。等价于 ’[^A-Za-z0-9_]’。
(68) \xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。
(69) \num 匹配 num,其中num是一个正整数。对所获取的匹配的引用。
(70) \n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
(71) \nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
(72) \nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
(73) \un 匹配 n,其中 n 是一个用四个十六进制数字表示的Unicode字符。
(74) 匹配中文字符的正则表达式: [u4e00-u9fa5]
(75) 匹配双字节字符(包括汉字在内):[^x00-xff]
(76) 匹配空行的正则表达式:n[s| ]*r
(77) 匹配HTML标记的正则表达式:/<(.)>.|<(.*) />/
(78) 中文、英文、数字及下划线:^[\u4e00-\u9fa5_a-zA-Z0-9]+$
(79) 匹配首尾空格的正则表达式:(^s*)|(s*$)
(80) 匹配Email地址的正则表达式:w+([-+.]w+)@w+([-.]w+).w+([-.]w+)*
(81) 匹配网址URL的正则表达式:http://([w-]+.)+[w-]+(/[w- ./?%&=]*)?
(82) 利用正则表达式限制网页表单里的文本框输入内容:
(83) 用正则表达式限制只能输入中文:οnkeyup=”value=value.replace(/[^u4E00-u9FA5]/g,”)” onbeforepaste=”clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^u4E00-u9FA5]/g,”))”
(84) 用正则表达式限制只能输入全角字符: οnkeyup=”value=value.replace(/[^uFF00-uFFFF]/g,”)” onbeforepaste=”clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^uFF00-uFFFF]/g,”))”
(85) 用正则表达式限制只能输入数字:οnkeyup=”value=value.replace(/[^d]/g,”) “onbeforepaste=”clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^d]/g,”))”
(86) 用正则表达式限制只能输入数字和英文:οnkeyup=”value=value.replace(/[W]/g,”) “onbeforepaste=”clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^d]/g,”))”
(87) 帐号(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
(88) 匹配中文字符的正则表达式: [\u4e00-\u9fa5]
(89) 匹配双字节字符(包括汉字在内):[^\x00-\xff]
(90) 匹配空行的正则表达式:\n[\s| ]*\r
(91) 匹配HTML标记的正则表达式:/<(.)>.<\/\1>|<(.*) \/>/
(92) 匹配首尾空格的正则表达式:(^\s*)|(\s*$)
(93) 匹配IP地址的正则表达式:/(\d+).(\d+).(\d+).(\d+)/g //
(94) 匹配Email地址的正则表达式:\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*
(95) 匹配网址URL的正则表达式:http://(/[\w-]+.)+[\w-]+(/[\w- ./?%&=]*)?
(96) sql语句:^(select|drop|delete|create|update|insert).*$
(97) 非负整数:^\d+$
(98) 正整数:^[0-9][1-9][0-9]$
(99) 非正整数:^((-\d+)|(0+))$
(100) 负整数:^-[0-9][1-9][0-9]$
(101) 整数:^-?\d+$
(102) 非负浮点数:^\d+(.\d+)?$
(103) 正浮点数:^((0-9)+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
(104) 非正浮点数:^((-\d+.\d+)?)|(0+(.0+)?))$
(105) 负浮点数:^(-((正浮点数正则式)))$
(106) 英文字符串:^[A-Za-z]+$
(107) 英文大写串:^[A-Z]+$
(108) 英文小写串:^[a-z]+$
(109) 英文字符数字串:^[A-Za-z0-9]+$
(110) 英数字加下划线串:^\w+$
(111) E-mail地址:^[\w-]+(.[\w-]+)*@[\w-]+(.[\w-]+)+$
(112) URL:^[a-zA-Z]+://(\w+(-\w+))(.(\w+(-\w+)))(\?\s)?$
或:^http:\/\/[A-Za-z0-9]+.[A-Za-z0-9]+[\/=\?%-&_~`@[]\’:+!]([^<>\”\”])$
(113) 邮政编码:^[1-9]\d{5}$
(114) 中文:^[\u0391-\uFFE5]+$
(115) 电话号码:^(((\d{2,3}))|(\d{3}-))?((0\d{2,3})|0\d{2,3}-)?[1-9]\d{6,7}(-\d{1,4})?$
(116) 手机号码:^(((\d{2,3}))|(\d{3}-))?13\d{9}$
(117) 双字节字符(包括汉字在内):^\x00-\xff
(118) 匹配首尾空格:(^\s*)|(\s*$)(像vbscript那样的trim函数)
(119) 匹配HTML标记:<(.)>.<\/\1>|<(.*) \/>
(120) 匹配空行:\n[\s| ]*\r
(121) 提取信息中的网络链接:(h|H)(r|R)(e|E)(f|F) = (‘|”)?(\w|\|\/|.)+(‘|”| *|>)?
(122) 提取信息中的邮件地址:\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*
(123) 提取信息中的图片链接:(s|S)(r|R)(c|C) = (‘|”)?(\w|\|\/|.)+(‘|”| *|>)?
(124) 提取信息中的IP地址:(\d+).(\d+).(\d+).(\d+)
(125) 提取信息中的中国手机号码:(86)*0*13\d{9}
(126) 提取信息中的中国固定电话号码:((\d{3,4})|\d{3,4}-|\s)?\d{8}
(127) 提取信息中的中国电话号码(包括移动和固定电话):((\d{3,4})|\d{3,4}-|\s)?\d{7,14}
(128) 提取信息中的中国邮政编码:[1-9]{1}(\d+){5}
(129) 提取信息中的浮点数(即小数):(-?\d*).?\d+
(130) 提取信息中的任何数字 :(-?\d*)(.\d+)?
(131) IP:(\d+).(\d+).(\d+).(\d+)
(132) 电话区号:/^0\d{2,3}$/
(133) 腾讯QQ号:^[1-9][1-9][0-9]$