JavaImprove--Lesson06--正则表达式

一.正则表达式的入门

正则表达式是一些特定支付组成的,代表一个规则,简化代码,以字符的形式体现规则

正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。

正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式的概念始于20世纪50年代,当时美国数学家StephenColeKleene正式提出了正则语言的概念。随着Unix文本处理工具的出现,正则表达式被普遍使用。

自20世纪80年代以来,存在不同的编写正则表达式的语法,其中一种是POSIX标准,另一种是广泛使用的Perl语法

入门程序:

我们需要简单校验一下中国的电话号码的合法性,有以下简单规则:

  • 以数字1开头
  • 长度为11位
  • 中间不包括字符

使用自己写的代码程序校验:

复制代码
public static void main(String[] args) {
//手写程序
System.out.println(checkPhoneNumber("17388268020"));//true
System.out.println(checkPhoneNumber(null));//false
System.out.println(checkPhoneNumber("12"));//false
System.out.println(checkPhoneNumber("12as6987412"));//false
}
//手动书写程序
public static boolean checkPhoneNumber(String number){
    if (number == null){
        return false;
    }
    if (number.length()!=11 || number.charAt(0)!='1'){
        return false;
    }
    for (int i = 1; i < number.length(); i++) {
        if (number.charAt(i) < '0' || number.charAt(i) >'9'){
            return false;
        }
    }
    return true;
}

使用正则表达式:

复制代码
public static void main(String[] args) {
//正则表达式
System.out.println(checkNumberUseRegex("17388268020"));//true
System.out.println(checkNumberUseRegex(null));//false
System.out.println(checkNumberUseRegex("12"));//false
System.out.println(checkNumberUseRegex("12as6987412"));//false

}
//正则表达式
public static boolean checkNumberUseRegex(String number){
    return (number!=null) && number.matches("[1]\\d{10}");
}

可以看到,代码很简单,很优雅,很简洁

就是有点看不懂,所以我们需要认识以下,一些正则表达式的符号

正则表达式的常用符号

1.字符类:只能匹配单个字符 ,[ ]

复制代码
 //1.字符类(只能匹配单个字符)
 System.out.println("a".matches("[abc]")); //true 只能是a,b,c
 System.out.println("e".matches("[abc]"));//false
 System.out.println("d".matches("[^abc]")); //ture 不能是a,b,c
 System.out.println("a".matches("[^abc]"));//false
 System.out.println("b".matches("[a-zA-Z]"));//true 范围是a~z,A~Z
 System.out.println("2".matches("[a-zA-Z]"));//false
 System.out.println("k".matches("[a-z&&[^bc]]"));// ture 范围是a~z,但是不包括bc
 System.out.println("b".matches("[a-z&&[^bc]]"));//false
 System.out.println("ab".matches("[a-z]"));//false  []只能匹配一个字符,第二字符是不能匹配的

2.预定义字符:只能匹配单个字符

. \d \D \s \S \w \W

复制代码
//2.预定义字符(只匹配单个字符)
//
// . \d \D \s \S \w \W
System.out.println("马".matches("."));//ture " . " 可以匹配任意字符
System.out.println("马马".matches("."));//false 只能匹配单个字符
//使用\d等字符定义的时候,一定要注意\代表转义,所以使用\d等,需要在加一个\,将\d的\转换掉,即\\d
System.out.println("3".matches("\\d"));//ture \d => 0~9
System.out.println("a".matches("\\d"));//false a不是数字
System.out.println(" ".matches("\\s"));//ture \s:代表一个空白字符
System.out.println("a".matches("\\s"));//false
System.out.println(" ".matches("\\S"));//false \S代表非空格
System.out.println("a".matches("\\S"));//ture
System.out.println("a".matches("\\w"));//ture 字符数字下划线:a~z,A~Z,0~9,_
System.out.println("_".matches("\\w"));//ture
System.out.println("9".matches("\\w"));//ture
System.out.println("马".matches("\\w"));//false
System.out.println("马".matches("\\W"));//ture 不能是 字符数字下划线
System.out.println("a".matches("\\W"));//false 

3.数量词

? * + {n} {n, } {n,m}

复制代码
//3.数量词
//?  *  +  {n}  {n, }  {n,m}
System.out.println("a".matches("\\w?")); //ture ? 0次或1次
System.out.println("".matches("\\w?"));// ture 没出现
System.out.println("abc".matches("\\?"));//false
System.out.println("abc12".matches("\\w*"));// * 代表 0次或多次
System.out.println("".matches("\\w*"));//ture
System.out.println("acb马".matches("\\w*"));//false
System.out.println("abc12".matches("\\w+"));//ture  + 代表 1次或多次
System.out.println("".matches("\\w+"));//false
System.out.println("acb马".matches("\\w+"));//false 出现:非字符数字下划线
System.out.println("acb".matches("\\w{3}"));//ture 出现3 次
System.out.println("abc".matches("\\w{3,}"));//ture 大于等于3次
System.out.println("abc".matches("\\w{3,6}"));//ture 大于等于 3次 ,小于等于 6次

4.其它几个常用的符号
(?i):忽略大小写 | :或 ():分组

复制代码
//4.其它几个常用的符号
//(?i)忽略大小写  | 或 ():分组
System.out.println("abc".matches("(?i)abc"));//ture a 被忽略大小写
System.out.println("Abc".matches("(?i)abc"));//ture
System.out.println("aBc".matches("ab(?i)c"));//false B没有被限制
System.out.println("abc".matches("123{3}|\\w{3}"));//ture 要么是123三个字符 或者 要么是字符数字下划线三个
System.out.println("123".matches("123{3}|\\w{3}"));//ture
System.out.println("马ac".matches("123{3}|\\w{3}"));//false
System.out.println("ababc".matches("(ab)+c"));//ture ab必须出现1次或多次
System.out.println("(acacb)".matches("(ab)+c"));//false
System.out.println("abab".matches("(ab)?"));//false ab出现0次或1次

二.正则表达式的应用

使用正则表达式来校验电话号码

复制代码
//检测电话号码是否合规
//可能是座机,可能是手机
public  static  boolean checkPhone(String num){
    //手机电话以1开始,第二位是3-7,长度一般是 11 位
    //座机号码一般是0开始,前三位是区号,中间可有可无 -符号,后面长度为5-20
    //号码全是数字,无字符
    return (num !=null) && (num.matches("(1[3-7]\\d{9})|(0\\d{2}-?[1-9]\\d{3,20})"));
}

正则表达式的写法其实就是在找字符串的规律:

复制代码
(1[3-7]\\d{9})|(0\\d{2}-?[1-9]\\d{3,20})

验证手机号:

首先在校验手机号码的时候,我们可以看到必须是以1开头的,所以正则表达式就需要在第一个位置占位1

而第二位我们也知道了只能在3~9中选择,因为我们并没有发现10,11,12开头的电话号码,所以第二位的取值区间也被限定了[3-9]

除开前两位数字以后,后面的就没什么要求了,除了全部都是数字没有其它的要求所以可以使用 \ \d 直接概括完

复制代码
(1[3-7]\\d{9})

验证座机号:

中间是有一个 | 符号的,它的作用是 :或的意思,也就是前面不匹配的时候可以试着匹配后面部分,在思想上就是如果不是手机号就是座机号

对于座机号我们也需要按照,字符串的规则来制定正则表达式

首先座机号码一般是0开始的,所以正则表达式直接使用0先占位

前三位只要是数字就行,所以可以直接使用 \\d{2},在匹配随机的任意两位数字就可以了

中间区号有些是需要使用 - 符号分割的,但是有些座机号又没有,所以按需使用就可以了,也就是 - 可以出现,也可以不出现,使用?就可以匹配 0 次或 1次

后面的就全部是数字 \\ d就可以搞定,然后限制一下,后面最多,最少可以拥有多少位数字就完成了

复制代码
(0\\d{2}-?[1-9]\\d{3,20})

使用正则表达式来校验邮箱账户

复制代码
//验证邮箱账户是否合理
//1425ms@163.com
//2021373@qq.com
//235676ll@msf.com.cn  二级域名
public  static  boolean checkEmail(String email){
    return (email!=null) && (email.matches("\\w{2,}@\\w{2,10}(\\.\\w{2,10})+"));
}

主要来来看看正则表达式部分:

复制代码
\\w{2,}@\\w{2,10}(\\.\\w{2,10})+

在验证邮箱账户的时候,每个邮箱账户有一个很明显的特点,它是使用@符号进行分割的

@前面部分都是由数字字符下划线组成的自定义用户名

@后面部分就是高级域名,他一般指代的是公司和区域位置,如腾讯的qq.com,网易的163.com等

所以在写正则表达式的时候也需要利用@将邮箱账户直接划分成两部分

前部分可以直接利用\\w解决,因为都是字符数组之类的,只用划定一下长度区间就好了,但是一般自定义的账户都是没有做长度限制的,都是在2个字符以上就可以了

@后面部分是高级域名区和公司称谓,都是\\w直接解决,限定长度就可以了,但是注意要加 . 符号,但是在正则表达式中 .是通配的意思,所以需要转义 \\ .

由于高级域名可能有两级,如:.com.cn,所以限定 \\. \\w{2,10} + ,出现 1次,或多次就可以了

使用正则表达式来查找信息

Pattern类:

在Java中,Pattern 类是用于表示正则表达式的一个类,它属于 java.util.regex 包。Pattern 类提供了一种将正则表达式编译为可重用的模式的方法,并且可以通过这些模式执行各种匹配操作。

使用 Pattern 类,可以将正则表达式编译为 Pattern 对象,然后使用该对象创建 Matcher 对象,以便在特定的输入字符串上执行匹配操作。可以使用 Matcher 对象的各种方法来执行匹配、查找和替换等操作。

简单来讲:使用pattern类利用Pattern.compile()方法,需要将一个正则表达式模板传入,而pattern.compile()方法就会根据正则表达式模板生成一个pattern对象,在进行文本匹配的时候,就会反复调用这个文本模板

matcher方法:

在Java中,Pattern 类的 matcher() 方法用于创建一个 Matcher 对象。Matcher 对象用于在给定的输入字符串上执行匹配操作。

当你有一个编译好的 Pattern 对象时,你可以使用 matcher() 方法来创建一个 Matcher 对象,然后使用该对象的各种方法来执行匹配、查找和替换等操作。

使用matcher方法就可以反复的查找给定的一段文本中的类容,如果文本类容中有一段符合正则表达式,则就返回ture,我们还可以matcher.group()方法将这段匹配的文本内容拿出来

代码测试:

复制代码
public static void main(String[] args) {
    String data ="来黑马程序员学习Java\n"+
            "电话:1866668888,18699997777\n"+
            "或者联系邮箱: boniu@itcast.cn\n" +
            "座机电话:01036517895,010-98951256\n" +
            "邮箱: bozai@itcast.cn\n" +
            "邮箱2:dleieo09@163.com\n"+
            "热线电话:400-618-9090 , 400-618-4008,4006184000,4006189090";
    //1.定义查询时数据规则,正则表达式
    //电话号码,座机号码,邮箱
    String regex ="(1[3-9]\\d{9})|(0\\d{2}-?[1-9]\\d{3,20})|(\\w{2,}@\\w{2,10}(\\.\\w{2,10}){1,2})|(400-?618-?[1-9]\\d{3,20})";
    //2.利用pattern.compile方法构造处一个pattern对象,利用正则表达式的模板
    Pattern pattern = Pattern.compile(regex);
    //3.利用pattern.matcher传入数据后,构造一个matcher对象,它会反复利用正则表达式遍历数据文本
    Matcher matcher = pattern.matcher(data);
    //匹配上数据后就可以输出了
    while (matcher.find()){
        System.out.println(matcher.group());
    }
}

正则表达式用来搜索替换内容,分割

替换内容使用replaceAll()方法:

public String replaceAll(String regex,String newStr)

其中regex参数需要传入的是一个正则表达式,而newStr则是需要替换的新字符串

按照正则表达式匹配上的文本,替换成新文本

复制代码
// public String replaceAll(String regex,String newStr)
//按照正则表达式匹配上的文本,替换成新文本
String txt1 = "正则表达式是1254真的好用12563,并且7852简洁,就是99864有点555难";
//将数字全部去掉
String s1 = txt1.replaceAll("\\w+", "");
System.out.println(s1); //正则表达式是真的好用,并且简洁,就是有点难

进阶版:

复制代码
 String txt2 = "我我我喜喜喜欢欢编编编编编编程程程程程程";
 //去掉多余的字符,每个字符只留下一个
 String s2 = txt2.replaceAll("(.)\\1+", "$1");
 //这里的\\1是分组的意思,表示1组,后面被替换的字符就是重出现的字符,也就是1组内的字符,使用$符 组号将其取出来
 System.out.println(s2); //我喜欢编程

分割内容使用的是spilt()方法:
public String[] spilt(String regex)
其中regex参数也是正则表达式
按照正则表达式匹配的内容进行分割,并且返回一个分割后的数组

复制代码
//public String[] spilt(String regex)
//按照正则表达式匹配的内容进行分割,并且返回一个分割后的数组
String txt3 = "原来你也玩原神3564a,不对,原神56688ooihb启动!";
//将汉字用非汉字分割成字符串数组
String[] s3 = txt3.split("\\w+");
System.out.println(Arrays.toString(s3));//[原来你也玩原神, ,不对,原神, 启动!]