正则表达式
正则表达式在本质上是一种字符串操作的语法规则,利用此语法规可以更加灵活地实现字符串的匹配,拆分,替换等操作。
1.问题引出
要求判断一个字符串是否由数字组成,在利用正则表达式之前实现字符串的判断:
- 为了能够判断每一位字符数据,需要将字符串转化为字符数组,这样可以便于循环判断。
- 判断字符数组中的每一个字符是否都在“‘0’-‘9’”范围内。
例1.实现字符串的判断
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception {
String str = "123yootk";
System.out.println(isNnumber(str));
}
/**
* 判断字符串是否由数字所组成,在本操作中首先将字符串转换为字符数组,然后循环判断每一位字符
* @param temp 要判断的字符串数据
* @return 如果字符串有非数字,为null,没有数据返回false,正确返回true
*/
public static boolean isNnumber(String temp){
if (temp == null){
return false;
}
char data[] = temp.toCharArray(); //字符串变为字符数组
for (int x = 0; x < data.length; x++){
if (data[x] > '9' || data[x] < '0'){ //有一个字符不是数字
return false;
}
}
return true;
}
}
观察此程序可知,判断某一个简单的字符串是否由数字组成是一个很容易实现的功能,且程序中的字符串很简单,代码却很麻烦。要是验证更加复杂的字符串(例如e-mail格式),代码就会变得更加麻烦。这时正则表达式就可以帮助用户简化此类代码的编写难度。
例2.利用正则表达式实现同样的验证
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception {
String str = "123yootk";
System.out.println(str.matches("\\d+"));
}
}
本程序实现了同样的验证功能,最重要的是,编写的代码非常有限,程序中出现的“\\d+”就是正则表达式。因此,利用正则表达式可以用简单的编写实现复杂的字符串操作。
2.正则标记(重要)
所有正则表达式支持的类都定义在 j a v a . u t i l . r e g e x \color{Coral}{java.util.regex} java.util.regex包里面。在此包中定义了如下两个重要的类。
- Pattern类:主要定义要使用的表达式对象
- Matcher类:用于进行正则标记与指定内容的匹配操作
所有可以使用的正则标记都在
j
a
v
a
.
u
t
i
l
.
r
e
g
e
x
.
P
a
t
t
e
r
n
\color{Coral}{java.util.regex.Pattern}
java.util.regex.Pattern类的文档中定义,常用的标记有如下六类。
(1).单个字符(数量:1)
- 字符:表示由一位字符组成;
- \\:表示转义字符“\”;
- \t:表示一个“\t”符号;
- \n:匹配换行(\n)符号;
(2).字符集(数量:1)(一组字符)
- [abc]:表示可能是字符a、字符b、字符c中的任意一位;
- [^abc]:表示不是字符a、字符b、字符c中的任意一位;
- [a-z]:所有的小写字母;
- [a-zA-Z]:表示任意的一位字符,不区分大小写;
- [0-9]:表示任意的一位数字;
(3).简化的字符集表达式(数量:1)
- .:表示任意的一位字符;
- \d:等价于“[0-9]”,属于简化写法;
- \D:等价于“[^0-9]”,属于简化写法;
- \s:表示任意的空白字符,例如:“\t” “\n”;
- \S:表示任意的非空白字符;
- \w:等价于“[a-zA-Z_0-9]”,表示由任意的字母、数字、_组成;
- \W:等价于“[^a-zA-Z_0-9]”,表示不是由任意的字母、数字、_组成;
(4).边界匹配
- ^:正则的开始;
- $:正则的结束;
(5).数量表达
- 正则?:表示此正则可以出现0次或1次;
- 正则+:表示此正则可以出现1次或1次以上;
- 正则*:表示此正则可以出现0次、1次或多次;
- 正则{n}:表示此正则正好出现n次;
- 正则{n,}:表示此正则出现n次以上(包含n次);
- 正则{n,m}:表示此正则出现n~m次(包含n次和m次);
(6).逻辑运算
- 正则1正则2:正则1判断完成后继续判断正则2;
- 正则1 | 正则2:正则1或者是正则2有一组满足即可;
- (正则):将多个正则作为一组,可以为这一组单独设置出现的次数。
3.String类对正则的支持
从实际使用而言,大部分情况下都会考虑使用 j a v a . l a n g . S t r i n g \color{Coral}{java.lang.String} java.lang.String类中提供的方法直接简化正则的操作。下表中定义了String类与正则有关的5个方法。
方法名称 | 描述 |
---|---|
public boolean matches (String regex) | 普通方法。正则验证,使用指定的字符串判断其是否符合给出的正则表达式结构 |
public String replaceAll(String regex, String replacement) | 普通方法。将满足正则标记的内容全部替换为新的内容 |
public String replaceFirst(String regex, String replacement) | 普通方法。将满足正则标记的首个内容替换为新的内容 |
public String[] split(String regex) | 普通方法。按照指定的正则标记进行字符串的全拆分 |
public String[] split(String regex, int limit) | 普通方法。按照指定的正则标记进行字符串的部分拆分 |
例3.实现字符串替换
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = "hello*)(*()yootk(*#mldn*";
String regex = "[^a-z]"; //此处编写正则
System.out.println(str.replaceAll(regex,"")); //字符串替换
}
}
例4.字符串拆分
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = "yootk9mldnyo9887o5555tk";
String regex = "\\d+"; //[0-9]一位以上
String result[] = str.split(regex);
for (int x = 0; x <result.length; x++){
System.out.println(result[x]);
}
}
}
本程序提供的字符串中存在许多数字,有的是一位有的是多位,所以在匹配数字时应该使用“+”作为量词,这样就对一位或多位数字进行拆分。
例5.验证一个字符串是否为数字,如果是则将其变为double型。
提示:要转换的数字可能是整数(10)也可能是小数(10.2),但绝不允许出现非数字,并且小数点出现时应该有对应的小数位。
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = "10.10";
String regex = "\\d+(\\.\\d+)?";
if (str.matches(regex)){ //转型之前要进行验证
System.out.println(Double.parseDouble(str));
}
}
}
例6.判断给定的字符串是否为一个IP地址
提示:以“192.168.1.1”IP地址为例,每一个段可以包含的数字长度为1~3位。
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception {
String str = "192.168.1.1";
String regex = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";
System.out.println(str.matches(regex));
}
}
本程序由于存在4组数据(“.”只有三个),并且每组数据都是由1~3位的数字组成,所以每组数字验证的正则格式为“\\d{1,3}”.同时在进行“.”匹配时必须转义,所以使用“\\.”。
例7.给定一个字符串,要求判断其是否是日期格式,如果是则将其转换为Date型数据。本次只验证“年-月-日”的日期格式,其中包含4位数字,月与日分别包含两位数字。
package com.yootk.demo;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = "2013-08-15";
String regex = "\\d{4}-\\d{2}-\\d{2}"; //定义验证规则
if (str.matches(regex)){ //符合规则
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(str);
System.out.println(date);
}
}
}
本程序首先编写正则进行了年、月、日3个数据的验证,由于在使用SimpleDataFormat时需要严格的匹配格式,所以在进行月和日编写时必须保证是两位的数字(\\d{2})。
例8.判断电话号码,一般是要编写电话号码满足以下3种格式。
- 格式一:51283346,一般长度是7~8位的数字是电话号码(正则格式为:“\\d{7,8}”);
- 格式二:010-51283346,区号一般是3~4位,而且区号和电话之间的“-”只有在出现区号时才出现,正则格式:“(\\d{3,4}-)?\\d{7,8}”;
- 格式三:(010)-51283346,其中在区号前的括号必须成对出现,这样就需要将括号与区号译器显示,正则格式为:“((\\d{3,4}-)|(\\(\\d{3,4}\\)-))?\\d{7,8}”;
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = "(010)-51283346";
String regex = "((\\d{3,4}-)|(\\(\\d{3,4}\\)-))?\\d{7,8}";
System.out.println(str.matches(regex));
}
}
例9.验证email地址,对于此验证有两种不同的格式要求
- 格式一:email由字母、数字、“_”组成。
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = "mldn_lixinghua100@yootk.com";
String regex = "\\w+@\\w+\\.\\w+";
System.out.println(str.matches(regex));
}
}
本程序的验证规则较为简单,在每一个email中“@”与“.”必须正常显示,所以此处直接编写具体的字符即可,由于其他组成部分没有要求,所以只要由一位或一位以上的字母、数字、“_”组成就满足验证条件。
- 格式二:用户名要求由字母、数字、“_”、“.”组成,其中必须以字母开头,结尾只能是字母或者数字,用户名长度为2~30,最后的域名后缀只能是.com、.cn 、.net、.com.cn、.net.cn、.edu、.gov、.org其中的一个。
package com.yootk.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "mldn.100_lixinghua@yootk.com";
String regex = "[a-zA-Z][a-zA-Z0-9_\\.]{0,28}[a-zA-Z0-9]" + "@\\w+\\.(com|net|cn|com\\.cn|net\\.cn|org|gov|edu)";
System.out.println(str.matches(regex));
}
}
本程序由于email用户名的组成较为严格,所以对于email的首字母(“[a-zA-Z]”)以及结尾字母([a-zA-Z0-9])必须单独定义规则,由于首尾各占了一个验证长度,所以中间的部分长度就需要控制在0~28位。对于域名的验证,由于是几个限定的域名结尾,所以需要给出若干个域名的使用范围,由于使用了或的概念,所以只需要满足一个标准即可通过验证。
4.java.util.regex支持
在大多数情况下使用正则表达式时都会采用String类完成,但是正则表达式最原始的开发包是 j a v a . u t i l . r e g e x \color{Coral}{java.util.regex} java.util.regex,利用本包中提供的Pattern与Matcher类也同样可以实现正则表达式。
java.util.Pattern类的主要功能是进行数据的拆分以及Matcher类对象实例化。
1.Pattern类常用的方法
方法 | 描述 |
---|---|
public static Pattern compile(String regex) | 普通方法,编译正则表达式 |
public String[] split (charSequence input) | 普通方法,数据全拆分操作 |
public String[] split(charSequence input, int limit) | 普通方法,数据部分拆分操作 |
public Matcher matcher(charSequence input) | 普通方法,取得Matcher对象 |
在Pattern类中没有定义构造方法,所以如果想要取得Pattern类对象,必须利用compile()方法进行指定正则表达式的编译操作。同时在Pattern类中定义的方法,在进行参数接收时接收的都是CharSequence接口对象,这样就表示只要是CharSequence接口的子类对象都可以进行正则操作。
例10.利用Pattern类实现字符串拆分
package com.yootk.demo;
import java.util.Arrays;
import java.util.regex.Pattern;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "hello1yootk22mldn333lixinghua";
String regex = "\\d+";
Pattern pattern = Pattern.compile(regex); //编译正则
String result[] = pattern.split(str); //拆分字符串
System.out.println(Arrays.toString(result));
}
}
本程序利用了Pattern类直接进行了字符串的拆分操作,首先将需要使用到的正则表达式利用compile()进行编译,然后直接调用Pattern类的split()方法实现拆分操作。
2.Matcher类的常用方法
方法 | 描述 |
---|---|
public boolean matches() | 普通方法。正则匹配 |
public String replaceAll(String replacement) | 普通方法。全部替换 |
public String replaceFirst(String replacement) | 普通方法。替换首个 |
如果想要进行数据的验证与替换操作,就需要通过Matcher类实现操作。
例11.实现字符串验证操作
package com.yootk.demo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = "100";
String regex = "\\d+";
Pattern pattern = Pattern.compile(regex); //编译正则
Matcher mat = pattern.matcher(str); //进行正则匹配
System.out.println(mat.matches()); //匹配结果
}
}
本程序首先利用Pattern类的matcher()方法取得Matcher类对象,然后利用matches()方法判断指定的字符串是否符合指定的正则规范。
参考资料:《Java第一行代码》,李兴华,马云涛著。人民邮电出版社。