正则表达式
认识正则
具体内容
通过之前的一系列的分析可以发现,String 一个非常万能的类型,因为 String 不仅仅可以支持有各种字符串的处理操作,也支持有向各个数据类型的转换功能,所以在项目的开发之中,只要是用户输入的信息基本上都可以用 String 表示。
于是再向其他类型转换的时候,为了保证转换的正确性,往往需要对其进行一些复杂的验证处理,这种情况下如果只是单纯的依靠 String 类中的方法是非常麻烦的。
认识正则表达式
现在假设有一个字符串要求你判断字符串是否由数字组成,如果由数字所组成则将变为数字进行乘法计算。
public class RegularTest {
public static void main(String[] args) {
String str = "123";
if (isNumber(str)){
System.out.println(Integer.parseInt(str) * 2);
}
}
private static boolean isNumber(String str) {
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] > '9' || chars[i] < '0')
return false;
}
return true;
}
}
实际上这种验证的功能是非常简单的,但是这如此简单的功能却需要开发者编写大量程序逻辑代码那么如果是更加复杂的验证呢?那么在这样的情况下,对于验证来讲最好的做法就是利用正则表达式来完成。
范例:使用正则表达式实现同样的效果
public static void main(String[] args) {
String str = "123";
if (str.matches("\\d+")){
System.out.println(Integer.parseInt(str) * 2);
}
}
正则表达式最早是从 Perl 语言里面发展而来的,而后在 JDK1.4 以前如果需要使用到正则表达式的相关定义则需要单独引入其他的 jar 文件,但是从 JDK1.4 之后,正则已经默认被 JDK 所支持,并且提供有 java.util.regex 开发包,同时针对于 String 类也提出进行了一些修改,使其可以有方法之间支持正则处理。
使用正则最大特点在于方便进行验证处理,以及方便进行复杂字符串的修改处理。
正则标记
1、【数量:单个】字符匹配
- 任意字符:表示由任意字符组成,匹配单个字符的:
String str = "a";
String regex = "a";
System.out.println(str.matches(regex)); // true
System.out.println("aa".matches(regex)); // false
System.out.println("b".matches(regex)); // false
\\
:匹配"\"\n
:匹配换行\t
:匹配制表符
2、【数量:单个】字符集匹配(可以从里面任选一个字符)
[abc]
:表示可能时字母a、b、c中的任意一个
// 匹配单个字符:
String str = "a";
String regex = "[a,b,c]";
System.out.println(str.matches(regex));// true
System.out.println("b".matches(regex));// true
System.out.println("ab".matches(regex));// false
[^abc]
:表示不是由a、b、c中的任意一个[a-zA-Z]
:表示由任意字母所组成,不区分大小写[0-9]
:表示由一个数字组成
String str = "3";
String regex = "[0-20]";// 如果输入大于10的数时就只能匹配0-数字的第一位
System.out.println(str.matches(regex));
3、【数量:单个】简化字符集
.
:表示任意的一个字符,什么都可以,数字,字母,符号,中文等等\d
:等价于 “[0-9]” 范围\D
:等价于 “[^0-9]” 范围\s
:匹配任意的一位空格,可能时空格、换行、制表符\S
:匹配任意的非空格数据\w
:匹配字母、数字、下划线,等价于 “[a-zA-z_0-9]”\W
:匹配非字母、数字、下划线
4、边界匹配
^
:匹配边界开始$$
:匹配边界结束
5、数量表示
默认情况下只有添加上了数量单位才可以匹配多为字符
- 表达式
?
:该正则可以出现0次或1次 - 表达式
*
:该正则可以出现0次、1次或多次 - 表达式
+
:该正则可以出现1次、多次 - 表达式{n}:表达式正好为n次
- 表达式{n,}:表达式的长度为n次以上
- 表达式{n,m}:表达式的长度为n-m
System.out.println("".matches("\\w+")); // false
System.out.println("abc".matches("\\w+")); // true
System.out.println("".matches("\\w*")); // true
System.out.println("abc".matches("\\w{3}*")); // true
System.out.println("abcd".matches("\\w{3}")); // false
System.out.println("abcd".matches("\\w{3,}")); // true
6、逻辑表达式
- XY:X表达式之后紧跟上Y表达式,例如:
"\\d[a-zA-Z]"
- X|Y:有一个表达式满足即可
- (X):为表达式设置一个整体描述,可以为整体描述设置一个整体范围
String类的正则支持
在进行正则表达式大部分处理的情况下都会基于 String 类来完成,并且在 String 类里面提供有如下与正则有关的操作方法:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
01 | public boolean matches(String regex). | 普通 | 将指定字符串进行正则判断。 |
02 | public String replaceAll(String regex, String | 普通 | 替换全部 |
03 | public String replaceFirst(String regex, String replacement): | 普通 | 替换首个 |
04 | public String[] split(String regex) | 普通 | 正则拆分 |
05 | public String[] split(String regex, int limit) | 普通 | 正则拆分 |
实现字符串的替换:
String str = "l;aksdjfq@#$p@#$ouw[3rpoio@#$%iawkjd;flaksnd'/lk$#@$";
String regex = "[^a-zA-z0-9]";
System.out.println(str.replaceAll(regex, "")); // laksdjfqpouw3rpoioiawkjdflaksndlk
实现字符串的拆分
String str = "11111aas222222asd33333333sdf4444444444asdf5555555";
String regex = "[a-zA-z]+";
Arrays.stream(str.split(regex)).forEach(t -> System.out.print(t+"、")); // 11111、222222、33333333、4444444444、5555555、
在正则处理的时候对于拆分与替换的操作相对容易一些, 但是比较麻烦的是数据验证部分。
判断一个数据是否为小数
如果是小数则将其变为 double 类型
String str = "100.1";// 100./100.12/100
String regex = "\\d+(\\.\\d+)?";
System.out.println(str.matches(regex));
判断一个字符串是否由日期所组成
如果是由日期所组成则将其转为 Date 类型。
String str = "1982-12-12";
String regex = "\\d{4}-\\d{2}-\\d{2}";
if (str.matches(regex)) {
System.out.println(new SimpleDateFormat("yyyy-mm-dd").parse(str));
}
正则只能判断格式,不能判断它的内容是否正确
判断电话号码
* 51283346:`\\d{7,8}`
* 01051283346:`(\\d{3,4})?\\d{7,8}`
* (010)-51283346:`(\\(\\d{3,4}\\)-)?(\\d{3,4})?\\d{7,8}`或者`(\\d{3,4}|\\(\\d{3,4}\\)-)?\\d{7,8}`
既然已经可以使用正则进行验证了,那么下面就可以利用其来实现一个 email 地址格式的验证。
验证email格式
* email 的用户名可以由字母、数字、下划线 所组成; (不应该使用下划线开头)
* email 的域名可以由字母、数字、\_、-所组成;
* 域名的后缀必须是:.cn、.com、 .net、 .com.cn、 .gov;
String str = "asd_as123dfawer@aser-a_212.com";
String regex = "[a-zA-z0-9]\\w+@\\w+\\.(cn|com|net|com\\.cn|gov)";
System.out.println(str.matches(regex));
这几种匹配操作时正则中最常用的匹配操作
java.util.regex 包支持
虽然在大部分的情况下都可以以利用 String 类实现正则的操作,但是也有一 些情况下需要使用到 java.util.regex 开发包中提供的正则处理类。
在这个包里面一共定义有两个类: Pattern (正则表达式编译)、Matcher (匹配)。
pattern 类
提供有正则表达式的编译处理支持:
public static Pattern
compile(String regex);
同时也提供有字符串的拆分操作:
public String[] split(CharSequence inpu);
String str = "asd_as123dfawer@aser-a_212.com";
String regex = "[^a-zA-Z]+";
Pattern pattern = Pattern.compile(regex); // 编译正则
Arrays.stream(pattern.split(str)).forEach(t -> System.out.println(t));
Matcher 类
实现了正则匹配的处理类,这个类的对象实例化依靠 Pattern类 完成:
Pattern类提供的方法:
public Matcher matcher(CharSequence input);
当获取了 Matcher 类的对象之后就可以利用该类中的方法进行如下操作:
- 正则匹配:
public boolean matches();
- 字符串替换:
public String replaceAll(String replacement)。
String str = "asd_as123dfawer@aser-a_212.com";
String regex = "[^a-zA-Z]+";
Pattern pattern = Pattern.compile(regex); // 编译正则
Matcher matcher = pattern.matcher(str);
System.out.println(matcher.replaceAll("")); // asdasdfaweraseracom
如果纯粹是以拆分,替换,匹配三种操作为例根本用不到 java.util.regex 开发包,只依靠 String 类就都可以实现了,但是 mather 类里面提供有一种分组的功能,而这种分组的功能是 String 不具备的。
String 不具备的功能
// 要取出#{***}标记中的所有内容
String str = "INSERT INTO student(name,age,grades) value(#{name},#{age},#{grades})";
String regex = "#\\{\\w+\\}";
Pattern pattern = Pattern.compile(regex); // 编译正则
Matcher matcher = pattern.matcher(str);
while (matcher.find()) { // 是否由匹配成功的内容
System.out.println(matcher.group(0).replaceAll("#|\\{|\\}",""));
}
PS:内容参考致阿里云培训中心