正则表达式

 

一、正则表达式:是对字符串执行模式匹配的技术

介绍:

1.一个正则表达式,就是用某种模式去匹配字符串的一个公式。很多人因
为它们看上去比较古怪而且复杂所以不敢去使用,不过,经过练习后,就觉得这些复杂的表达式写起来还是相当简单的,而且,一旦你弄懂它们,你就能把数小时辛苦而且易错的文本处理工作缩短在几分钟(甚至几秒钟)内完成
2.特别强调,正则表达式不是只有java才有,实际上很多编程语
言都支持正则表达式进行字符串操作!如图所示。

 

 

 简单测试:对模式对象和匹配器的使用

package com.zjl.test.regexp;

import org.junit.jupiter.api.Test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp {
    @Test
    public void testRegexp(){
        //需要用正则表达式匹配的文字
        String content = "1994年10月,HotJava和Java平台为公司高层进行演示。1994年,Java 1.0a版本已经可以提供下载," +
                "但是Java和HotJava浏览器的第一次公开发布却是在1995年5月23日SunWorld大会上进行的。SUN公司的科学指导约" +
                "翰·盖吉宣告Java技术。这个发布是与网景公司的执行副总裁马克·安德森的惊人发布一起进行的,宣布网景将在其浏览" +
                "器中包含对Java的支持。1996年1月,升阳公司成立了Java业务集团,专门开发Java技术。";

        //其中\\d表示匹配一个数字
        String grammar = "(\\d\\d)(\\d\\d)";
        //创建一个模式对象,即正则表达式对象
        Pattern pattern = Pattern.compile(grammar);
        //创建一个匹配器,按照正则表达式的规则对content对象进行匹配
        Matcher matcher = pattern.matcher(content);

        int n = 0;
        while (matcher.find()) {
            //如上对正则表达式的匹配规则中加上了()
            // 那么matcher.group(0)表示该规则匹配到的整体即(\d\d)(\d\d)
            //matcher.group(1)就是group(0)所对应的规则的第一个括号
            //matcher.group(2)就是group(0)所对应的规则的第二个括号
            System.out.println("结果"+n+"展示:"+matcher.group(0));
            System.out.println("结果"+n+"展示:"+matcher.group(1));
            System.out.println("结果"+(n++)+"展示:"+matcher.group(2));
        }
        /**
         * 结果0展示:1994
         * 结果0展示:19
         * 结果0展示:94
         */

    }
}

二、正则表达式语法

基本介绍:运用正则表达式,必须了解其中各种元字符的功能,元字符从功能上大致分为6种:

1.限定符

2.选择匹配符
3.分组组合和反向引用符

4.特殊字符
5.字符匹配符

6.定位符

元字符(Metacharacter)——转义号(\\)

\\符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错的。
例如:用(去匹配"abc$(”,在IDEA中编译就会出错

提示:在Java的正则表达式式中,两个\\代表其他语言中的一个\

需要用到转义符号的字符有以下:( . *  +  ( )  $  /  \   ?  [ ]  ^  {  }  )

字符匹配符

 

 

 

 

 

 应用实例:

(1)[a-z]说明:

[a-z]表示可以匹配a-z中任意一个字符,比如[a-z]、[A-Z]去匹配 a11c8 ,[a-z]会得到结果ac

[A-Z]不会有任何结果,区分大小写;

(2). java正则表达式默认是区分字母大小写的,如何实现不区分大小写

(?I)abc表示abc都不区分大小写
a(?i)bc表示bc不区分大小写
a((?i)b)c表示只有b不区分大小写

//表示匹配时不会区分大小写
Pattern pattern = Pattern.compile(grammar, Pattern.CASE_INSENSITIVE);

[A-Z]表示可以匹配A-Z中的任意一个字符。

[0-9]表示可以匹配0-9中任意一个字符。

(3)

[^A-Z]:表示可以匹配不是a-z中的任意一个字符

[^a-z]:表示可以匹配不是A-Z中的任意一个字符

[^0-9]:表示可以匹配不是0-9中的任意一个字符

(4).[abcd]表示可以匹配abcd中的任意一个字符。
(5).[^abcd]表示可以匹配不是abcd中的任意一个字符。
当然上面的abcd你可以根据实际情况修改,以适应你的需求
(6).\\d表示可以匹配0-9的任意一个数字,相当于[0-9]。
(7).\\D表示可以匹配不是0-9中的任意一个数字,相当于[^0-9]

(8).\\w匹配任意英文字符、数字和下划线,相当于[a-zA-Z0-9_]

(9). \\W相当于[^a-zA-Z0-9]和\\w刚好相反.
(10).\\s 匹配任何空白字符(空格,制表符等)
(11).\\S 匹配任何非空白字符,和\\s刚好相反
(12)(.)点匹配出\n 之外的所有字符,如果要匹配.本身则需要使用\\。

选择匹配符:在匹配某个字符串的时候是选择性的,即:既可以匹配这个,又可以匹配那个,这时就需要选择匹配符号 (|)

 限定符:用于指定其前面的字符和组合项连续出现多少次

 

 

 java匹配是默认贪婪匹配,即尽可能匹配多的

 

 

 定位符:规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置,这个也是想当有用的

 

 

 分组:

 

 

特别分组: 

 

 

 对正则表达式的小应用:检查中文,数字长度,验证电话号码首部,验证url

package com.zjl.test.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp01 {
    public static void main(String[] args) {
        //待验证的内容
//        String content = "你好啊1245欢迎你";
        //验证邮箱内容/QQ号是否正确
//        String content = "18745123453";
        //匹配内容为url
        String content = "https://www.bilibili.com/video/BV*1fh411y7R8?p=894&spm_id_from=pageDriver";
        //验证汉字[\u0391-\uffe5]表示所有的汉字
//        String regStr = "^[\u0391-\uffe5]+$";
        //验证邮政编码
//        String regStr = "^\\d{6}$";
        //检查一个QQ号是不是正常在5到10位的数字
//        String regStr = "^\\d{5,10}$";
        //验证电话号码是否11位并且是13,14,15,17,18 开头的
//        String regStr = "^1[3|4|5|7|8]\\d{9}$";
        /**
         * ^((http|https)://)? 字符串开始(^)匹配https://,?表示可以有一个或者没有
         * ([\w-]+\.)+匹配一到多个www.bilibili.xxxx.的结构
         * [\w-]+匹配多个字符数字下滑线和-(相当于此时com部分)
         * (\\/[\w-=.&?/%#*]*)?$表示匹配//www.bilibili.com之后/开始后的所有
         * 其中*表示0或多个,在[-=.&?/%#*]里的这些符号就表示符号本身的含义
         */
//        String regStr = "^((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-=.&?*/%#]*)?$";
        String regStr = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(.)*$";//其中(.)表示匹配除了\n以外的所有字符
        //模式器
        Pattern pattern = Pattern.compile(regStr);
        //匹配器
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println("找到:" + matcher.group());
        }
    }

}

二、正则表达式三个常用类

java.util.regex包主要包括以下三个类 Pattern类、Matcher 类和PatternSyntaxException

Pattern类
pattern对象是一个正则表达式对象。Pattern类没有公共构造方法。要创建一个Pattern对象,调用其公共静态方法,它返回一个 Pattern对象。该方法接受一个正则表达式作为它的第一个参数,比如:Patternr = Pattern.compile(pattern);

表示完整匹配:与matcher不同,matcher只是在内容中查找符合规范模式的字符串

而matches是模式规范必须完全匹配文本内容

patter.matches(匹配语法,匹配内容);
Matcher 类
Matcher对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共构造方法。你需要调用Pattern对象的matcher 方法来获得一个Matcher对象

 

 

 

 

 

 

.PatternSyntaxException
PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

分组、捕获、反向引用:

1.分组
我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式/一个分组。
2.捕获
把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式
3.反向引用
圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用(\\)分组号,外部反向引用($)分组号

反向引用测试:

 

 

 注意:对于反向引用,在模式条件的内部需要使用(\\),而在外部则需要使用($)

 //反向引用就是根据分组,对分组的组号用(\\)进行引用
        // (\\1:表示引用第一个分组{2}表示在引用一次之后再加上2次引用)
        String test = "(\\d)(\\d)\\2\\1";//模式规则:4554,7997
        String test1 = "^\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
        content = "12321-333999111";
        Pattern pattern = Pattern.compile(test1);
        //匹配器
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group());
        }
//结果为:
//找到:12321-333999111
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExpReplace {
    public static void main(String[] args) {

        String content = "救救急丫丫哈哈哈哈在不在在?";//救急丫哈在不在?

        String regstr = "(.)\\1+";//模式的规则

        Pattern pattern1 = Pattern.compile(regstr);//创建一个模式对象
        Matcher matcher1 = pattern1.matcher(content);//创建一个匹配器

        while (matcher1.find()) {
            System.out.println("找到:"+matcher1.group(0));//找到匹配的字符串
        }
        //将找到的字符串替换为该字符串的第一个分组,达到去重的效果,返回替换后的字符串
            String s = matcher1.replaceAll("$1");
            System.out.println(s);
        //简便省略的方法
         content = Pattern.compile(regstr).matcher(content).replaceAll("$1");
        System.out.println(content);
    }
}

三、String类中使用正则表达式

1、替换功能

 

 

 2、分割功能

 

 

 代码测试:

@Test
    public void RegExp02(){
        //将JDK1.3和JDK1.4替换成JDK
        String content = "JDK1.3还有JDK1.4以及之后JDK1.5还是JDK1.4重要";
        String regStr = "(JDK)1.(3|4)";
        //使用模式器和匹配器对进行替换操作
        System.out.println(Pattern.compile(regStr).matcher(content).replaceAll("$1"));

        //字符串的替换操作,变得相对于简单
        System.out.println(content.replaceAll("(JDK)1.(3|4)", "$1"));

        //将字符串分离,分组,可采用正则表达式,更加的方便
        String[] split = content.split("[.]");
        for (String s : split) {
            System.out.println(s);
        }
    }

//结果:

/*JDK还有JDK以及之后JDK1.5还是JDK重要
JDK还有JDK以及之后JDK1.5还是JDK重要
JDK1
3还有JDK1
4以及之后JDK1
5还是JDK1
4重要*/


简单的去重测试,string字符串的替换和分组(用正则表达式)

package com.zjl.test.regexp;

import org.junit.jupiter.api.Test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExpReplace {
    public static void main(String[] args) {

        String content = "救救急丫丫哈哈哈哈在不在在?";//救急丫哈在不在?

        String regstr = "(.)\\1+";//模式的规则

        Pattern pattern1 = Pattern.compile(regstr);//创建一个模式对象
        Matcher matcher1 = pattern1.matcher(content);//创建一个匹配器

        while (matcher1.find()) {
            System.out.println("找到:"+matcher1.group(0));//找到匹配的字符串
        }
        //将找到的字符串替换为该字符串的第一个分组,达到去重的效果,返回替换后的字符串
            String s = matcher1.replaceAll("$1");
            System.out.println(s);
        //简便省略的方法
         content = Pattern.compile(regstr).matcher(content).replaceAll("$1");
        System.out.println(content);
    }

    @Test
    public void RegExp02(){
        //将JDK1.3和JDK1.4替换成JDK
        String content = "JDK1.3还有JDK1.4以及之后JDK1.5还是JDK1.4重要";
        String regStr = "(JDK)1.(3|4)";
        //使用模式器和匹配器对进行替换操作
        System.out.println(Pattern.compile(regStr).matcher(content).replaceAll("$1"));

        //字符串的替换操作,变得相对于简单
        System.out.println(content.replaceAll("(JDK)1.(3|4)", "$1"));

        //将字符串分离,分组,可采用正则表达式,更加的方便
        String[] split = content.split("[.]");
        for (String s : split) {
            System.out.println(s);
        }

    }
    @Test
    public void homeWork01(){
        String content = "zjlq@q.com.cn";
        String regStr = "[\\w]+@([\\w]+\\.)+[\\w]+";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        if (content.matches(regStr)) {
            System.out.println("匹配成功");
        } else {
            System.out.println("匹配失败~");
        }

        System.out.println( matcher.matches());
//经过上面的强制匹配之后,已经到达字符串的最后,所以找不到
        while (matcher.find()) {
            System.out.println("找到:"+matcher.group());
        }
    }
    @Test
//    要求验证是不是整数或者小数
//    提示:这个题要考虑正数和负数
//    123 -345 34.89 -87.9 -0.01 0.45等

    public void homeWork02(){
        String content = "-78.23";
        String regStr = "^[-+]?([1-9]\\d*|0)(\\.\\d+)?$";
        if (content.matches(regStr)) {
            System.out.println("匹配成功~");
        } else {
            System.out.println("匹配失败~");
        }
    }
    @Test
    //获取网页的协议,域名,端口,以及页面文件
    public void homeWork03(){
        String content = "Https://www.baidui.com:8080/index/admin/table.html";
        String regStr = "^(\\w+)://([a-zA-Z.]+):(\\d+)[\\w/]*/([\\w.]+)$";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(1));
            System.out.println(matcher.group(2));
            System.out.println(matcher.group(3));
            System.out.println(matcher.group(4));
        }
    }
}

 常用正则表达式:

一、校验数字的表达式




1 数字:^[0-9]*$
2 n位的数字:^\d{n}$
3 至少n位的数字:^\d{n,}$
4 m-n位的数字:^\d{m,n}$
5 零和非零开头的数字:^(0|[1-9][0-9]*)$
6 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
7 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
8 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
9 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
10 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
11 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
12 非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13 非负整数:^\d+$ 或 ^[1-9]\d*|0$
14 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
15 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$




二、校验字符的表达式




1 汉字:^[\u4e00-\u9fa5]{0,}$
2 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
3 长度为3-20的所有字符:^.{3,20}$
4 由26个英文字母组成的字符串:^[A-Za-z]+$
5 由26个大写英文字母组成的字符串:^[A-Z]+$
6 由26个小写英文字母组成的字符串:^[a-z]+$
7 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
8 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
9 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
12 禁止输入含有~的字符:[^~\x22]+




三、特殊需求表达式




1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3 InternetURL:[a-zA-z]+://[^\s]* 或 ^https://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 
6 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
7 身份证号:
        15或18位身份证:^\d{15}|\d{18}$
        15位身份证:^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$
        18位身份证:^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
8 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
9 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
11 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 
12 日期格式:^\d{4}-\d{1,2}-\d{1,2}
13 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
14 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$ 
15 钱的输入格式:
16 1.有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$ 
17 2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$ 
18 3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$ 
19 4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$ 
20 5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$ 
21 6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$ 
22 7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ 
23 8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ 
24 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
25 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
26 中文字符的正则表达式:[\u4e00-\u9fa5]
27 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
28 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
29 HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
30 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
31 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
32 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
33 IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)

 

posted @ 2021-09-10 11:13  代码红了一大片  阅读(163)  评论(0编辑  收藏  举报