当前位置: 首页 > article >正文

正则表达式(Java)(韩顺平笔记)

正则表达式(Java)

底层实现

package com.hspedu.RegExp;

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

public class RegExp00 {
    public static void main(String[] args) {
        String content = "1998年12月8日,第二代Java平台的企业版J2EE发布。" +
                "1999年6月,Sun公司发布了第二代Java平台(简称为Java2)的3个版本:" +
                "J2ME(Java2 Micro Edition,Java2平台的微型版),应用于移动、无线及" +
                "有限资源的环境;J2SE(Java 2 Standard Edition,Java 2平台的标" +
                "准版),应用于桌面环境;J2EE(Java 2Enterprise Edition,Java 2平台" +
                "的企业版),应用于基于Java的应用服务器。Java 2平台的发布,是Java发展" +
                "过程中最重要的一个里程碑,标志着Java的应用开始普及。";
//        String regStr = "\\d\\d\\d\\d";
        String regStr = "(\\d\\d)(\\d\\d)";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        /**
         * matcher.find() 完成的任务
         * 1. 根据指定的规则,定位满足规则的子字符串(比如1998)
         * 2. 找到后,将子字符串的开始的索引记录到matcher对象的属性int[] groups;
         *    group[0] = 0, 把该子字符串的结束的索引+1的值记录到 groups[1] = 4;
         * 3. 同时记录 oldLast 的值为 子字符串的结束的 索引+1的值即4 即下次执行find时 就从4开始匹配
         *
         * matcher.find() 完成的任务
         * 1. 根据指定的规则,定位满足规则的子字符串(比如(19)(98))
         * 2. 找到后,将子字符串的开始的索引记录到matcher对象的属性int[] groups;
         *    2.1 group[0] = 0, 把该子字符串的结束的索引+1的值记录到 groups[1] = 4;
         *    2.2 记录1组的()匹配到的字符串 groups[2] = 0 groups[3] = 2
         *    2.3 记录2组的()匹配到的字符串 groups[4] = 2 groups[5] = 4
         * 3. 同时记录 oldLast 的值为 子字符串的结束的 索引+1的值即4 即下次执行find时 就从4开始匹配
         */
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
            System.out.println("找到:" + matcher.group(1));//表示匹配到的子字符串的第一组子串
            System.out.println("找到:" + matcher.group(2));//表示匹配到的子字符串的第二组子串
            //分组不能越界
        }
    }
}

matcher.find

public boolean find() {
        int nextSearchIndex = last;
        if (nextSearchIndex == first)
            nextSearchIndex++;

        // If next search starts before region, start it at region
        if (nextSearchIndex < from)
            nextSearchIndex = from;

        // If next search starts beyond region then it fails
        if (nextSearchIndex > to) {
            for (int i = 0; i < groups.length; i++)
                groups[i] = -1;
            return false;
        }
        return search(nextSearchIndex);
    }

matcher.group

public String group(int group) {
        if (first < 0)
            throw new IllegalStateException("No match found");
        if (group < 0 || group > groupCount())
            throw new IndexOutOfBoundsException("No group " + group);
        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
            return null;
        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
    }

基础用法

package com.hspedu.RegExp;

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

public class RegExp01 {
    public static void main(String[] args) {
        String content = "a_bchHKKay66 66sABc_jdj*@fDH \n  Y298HU 寒冷 韩顺平 han";
//        String regStr = "[a-z]";// 查找小写字母a-z任意一个字符
//        String regStr = "[A-Z]";// 查找大写字母A-Z任意一个字符
//        String regStr = "abc";// 查找abc字符串 (默认区分大小写)
//        String regStr = "(?i)abc";// 查找abc字符串 (不区分大小写)
//        String regStr = "[0-9]";// 查找0-9任意一个字符
//        String regStr = "[^0-9]";// 查找不在0-9任意一个字符
//        String regStr = "[^a-z]";// 查找不在a-z任意一个字符
//        String regStr = "[abcd]";// 查找abcd任意一个字符
//        String regStr = "[^abcd]";// 查找不是abcd任意一个字符
//        String regStr = "\\D";// 查找不是数字0-9字符
//        String regStr = "\\w";// 查找字母,数字,下划线  @不属于范围
//        String regStr = "\\W";// 上式取反 相当于[^0-9a-zA-Z_]
//        String regStr = "\\s";// 查找空白字符
//        String regStr = "\\S";// 查找非空白字符
//        String regStr = ".";// 查找非 \n 以外所有字符 查找.需要用 \\.

        String regStr = "寒|韩|han";// 选择匹配符


        //Pattern.CASE_INSENSITIVE 表示匹配不区分大小写
        Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);// 创建对象
        Matcher matcher = pattern.matcher(content);

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

正则限定符

符号含义示例说明匹配输入
*指定字符重复0次或n次(无要求)(abc)*仅包含任意个abc字符串,相当于\w*abc abcabcabc
+指定字符重复1次或n次(至少1次)m+(abc)*以至少1个m开头,后接任意个abc的字符串m mabc mabcabc
?指定字符重复0次或1次(最多1次)m+abc?以至少1个m开头,后接ab或abc的字符串mab mabc mmmab mmabc
{n}只能输入n个字符[abcd]{3}由abcd中字母组成的任意长度为3的字符串abc dbc adc
{n,}指定至少n个匹配[abcd]{3,}由abcd中字母组成的任意长度不小于3的字符串aab dbc aaabdc
{n,m}指定至少n个但不多于m个匹配[abcd]{3,5}由abcd中字母组成的任意长度不小于3,不大于5的字符串abc abcd aaaaa bcdab
package com.hspedu.RegExp;

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

public class RegExp02 {
    public static void main(String[] args) {
        String content = "11111111aaaaaaahello";

//        String regStr = "a{3}";// 匹配 aaa
//        String regStr = "1{4}";// 匹配 1111
//        String regStr = "\\d{2}";// 匹配 两位任意数字字符

        //Java默认匹配多的(贪婪匹配)
//        String regStr = "a{3,4}";// 匹配 aaa 或 aaaa(优先)
//        String regStr = "1{4,5}";// 匹配 1111 或 11111(优先)
//        String regStr = "\\d{2,5}";// 匹配 2位数 或 3,4,5 实际 sout (找到 11111 (换行) 找到 111)

//        String regStr = "1+";// 匹配 1个1 或 多个1
//        String regStr = "\\d+";// 匹配 1个数字 或 多个数字

//        String regStr = "1*"; // 匹配0个1或者多个1

        String regStr = "a1?";// 匹配 a 或 a1

        Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(content);

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

正则定位符

符号含义示例说明匹配输入
^指定起始字符1+[a-z]*以至少一个数字开头,后接任意个小写字母的字符串123 6aa 555edf
$指定结束字符2\\-[a-z]+$以一个数字开头后接连字符“-”,并以至少1个小写字母结尾的字符串1-a
\\b匹配目标字符串的边界han\\b这里说的字符串边界指的是子串间有空格,或者是目标字符串的结束位置hanshunping sphan nnhan
\\B匹配目标字符串的非边界han\\B和\b的含义相反hanshuping sphan nnhan
package com.hspedu.RegExp;

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

public class RegExp03 {
    public static void main(String[] args) {
//        String content = "123anj-556abc-945BGh";
//        String content = "123-ljj";
        String content = "hanshunping sphan nnhan";

//        String regStr = "^[0-9]+[a-z]*";// 找到123anj
//        String regStr = "^[0-9]+\\-[a-z]+$";// 找到123-ljj
//        String regStr = "^[0-9]+\\-[a-z]+$";// 找到123-ljj

//        String regStr = "han\\b";// 找到 han (sphan) 找到 han (nnhan)
        String regStr = "han\\B";// 找到 han (hanshunping)


        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

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

捕获分组

常用分组构造形式说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号。
(?'name’pattern)命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用尖括号代替单引号。
package com.hspedu.RegExp;

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

public class RegExp04 {
    public static void main(String[] args) {
        String content = "hanshunping s7789 nn1189han";

//        String regStr = "(\\d\\d)(\\d\\d)";//匹配四个数组的字符串(7789)(1189)

//        String regStr = "(\\d\\d)(\\d)(\\d)";
        /**
         * 找到 7789
         * 第一个分组 77
         * 第二个分组 8
         * 第三个分组 9
         * 找到 1189
         * 第一个分组 11
         * 第二个分组 8
         * 第三个分组 9
         */

        String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";
        /**
         * 找到 7789
         * 第一个分组[编号] 77
         * 第二个分组[编号] 89
         * 找到 1189
         * 第一个分组[编号] 11
         * 第二个分组[编号] 89
         */

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println("找到 " + matcher.group(0));
//            System.out.println("第一个分组 " + matcher.group(1));
            System.out.println("第一个分组[编号] " + matcher.group("g1"));
//            System.out.println("第二个分组 " + matcher.group(2));
            System.out.println("第二个分组[编号] " + matcher.group("g2"));
//            System.out.println("第三个分组 " + matcher.group(3));
        }
    }
}

非捕获分组

常用分组构造形式说明
(?:pattern)匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用“or”字符(|)组合模式部件的情况很有用。
(?=pattern)它是一个非捕获匹配。
(?!pattern)该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。
package com.hspedu.RegExp;

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

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

        String content = "hello韩顺平教育 Jack韩顺平老师 韩顺平同学hello";
        //找到 韩顺平教育 、 韩顺平老师 、 韩顺平同学
//        String regStr = "韩顺平(?:教育|老师|同学)";//不能group(1)

        //找到 韩顺平教育中的韩顺平 韩顺平老师中的韩顺平
//        String regStr = "韩顺平(?=教育|老师)";

        //找到 不是韩顺平教育中的韩顺平 不是韩顺平老师中的韩顺平
        String regStr = "韩顺平(?!教育|老师)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            //非捕获分组 不能使用group(1)
            System.out.println("找到 " + matcher.group(0));
        }
    }
}

非贪婪匹配

package com.hspedu.RegExp;

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

public class RegExp06 {
    public static void main(String[] args) {
        
        String content = "hello1111111";
        String regStr = "\\d+?";
        
        /**
         * 找到 1
         * 找到 1
         * 找到 1
         * 找到 1
         * 找到 1
         * 找到 1
         * 找到 1
         */
        
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            //非捕获分组 不能使用group(1)
            System.out.println("找到 " + matcher.group(0));
        }
    }
}

应用实例

package com.hspedu.RegExp;

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

public class RegExp07 {
    public static void main(String[] args) {
        //汉字
//        String content = "韩顺平教育";
//        String regStr = "^[\u0391-\uffe5]+$";//true

        //1-9开头的一个六位数
//        String content = "112344";
//        String regStr = "^[1-9]\\d{5}$";//true

        //1-9开头的一个(5-10位数)
//        String content = "12389";
//        String regStr = "^[1-9]\\d{4,9}$";//true

        //以11、13、18开头的11位数
        String content = "11588889999";
        String regStr = "^1[1|3|8]\\d{9}$";//true

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        if (matcher.find()) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }

    }
}

验证复杂URL

package com.hspedu.RegExp;

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

public class RegExp09 {
    public static void main(String[] args) {
        String content = "https://www.bilibili.com/video/BV1fh411y7R8?;
        /** ((http|https)://)开始部分
         *  ([\w-]+\.)+[\w-]+ 匹配 www.bilibili.com
         *  (\/[\w-?=&/%.#]*)? 匹配 /video/BV1fh411y7R8?p=894&vd_source=a8223634aa8a190c7233a2dc3f8a15e3
         *  []里面的元素相当于一个集合
         *  如果查找 "(去掉http)edu.metastudy.vip/mt/official/pc/mxmt-ksjhdj"
         *  regStr = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
         */

        String regStr = "^((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        if (matcher.find()) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }
    }
}

Pattern类matches方法

package com.hspedu.RegExp;

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

public class RegExp10 {
    public static void main(String[] args) {
        String content = "10https://www.bilibili.com/video/BV1fh411y7R8?p=894&vd_source=";

        String regStr = "((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        //find匹配必须加^$定位符
        if (matcher.find()) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }

        //整体匹配
        System.out.println(Pattern.matches(regStr, content));

        /**
         * true
         * false
         */
    }
}

Pattern类中的源码:

public static boolean matches(String regex, CharSequence input) {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(input);
        return m.matches();
    }

matcher方法

package com.hspedu.RegExp;

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

public class RegExp11 {
    public static void main(String[] args) {
        String content = "hello edu jack hspedutom hello smith hello";
//        String regStr = "hello";
        String regStr = "hello edu jack tom hello smith hello";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println("================");
            System.out.println(matcher.start());
            System.out.println(matcher.end());
            System.out.println(content.substring(matcher.start(),matcher.end()));
        }

        System.out.println("整体匹配 " + matcher.matches());

        regStr = "hspedu";
        pattern = Pattern.compile(regStr);
        matcher = pattern.matcher(content);

        String newContent = matcher.replaceAll("韩顺平教育");//并没有改变原来的content
        System.out.println("content = " + content);
        System.out.println("new = " + newContent);

    }
}

反向引用

  1. 分组 可以使用()组成一个比较复杂的匹配模式,一个圆括号的部分我们可以看作一个子表达式/一个分组
  2. 捕获 把正则表达式中子表达式/分组匹配内容,保存到一个组里,方便后面引用 0代表整个表达式
  3. 反向引用 圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式
package com.hspedu.RegExp;

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

public class RegExp12 {
    public static void main(String[] args) {
        String content = "hello hspedu11111 hello22 12345-111222333";

        //找到两个连续相同的数字
//        String regStr = "(\\d)\\1";

        //找到五个连续相同的数字
//        String regStr = "(\\d)\\1{4}";

        //找到个位与千位相同 十位与百位相同的数字
//        String regStr = "(\\d)(\\d)\\2\\1";

        //找到以下格式 "五位数-九位数连续每三位相同(例如:12345-111222333)"
        String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

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

替换分割匹配

package com.hspedu.RegExp;

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

public class RegExp13 {
    public static void main(String[] args) {
        String content = "我....我要....学学学学....编程java!";

        //去掉所有的 .
        Pattern pattern = Pattern.compile("\\.");
        Matcher matcher = pattern.matcher(content);
        content = matcher.replaceAll("");

        System.out.println("content=" + content);

        //去掉重复的字 (.)查找任意的字符 \\1反向引用出'(.)'的内容 +指重复多次 $1表示重复字符替换为1个
        //如果要替换ABAB型 例如"我要我要" 使用(..)\\1+
        content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");

        System.out.println("content=" + content);
    }
}

练习题

package com.hspedu.RegExp;

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

public class RegExpHomework {
    public static void main(String[] args) {
        //匹配电子邮箱 例如 shu@sohu.com shu@sougo.org.cn
        String content01 = "shu@sougo.org.cn";

        //[\\w-](@前面的英文) @([a-zA-z]+\.)(至少匹配一次@英文.)
        String regStr01 = "^[\\w-]+@([a-zA-z]+\\.)+[a-zA-Z]+$";

        if (content01.matches(regStr01)) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }

        //匹配整数或者小数
        String content02 = "-0.56";

        //([1-9]\d*|0)判断整数部分 不能出现0034.56
        String regStr02 = "^[-+]?([1-9]\\d*|0)(\\.\\d+)?$";

        if (content02.matches(regStr02)) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }

        //解析url
        String content03 = "http://www.sohu.com:8080/abc/index.html";

        String regStr03 = "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.]+)$";

        Pattern pattern = Pattern.compile(regStr03);
        Matcher matcher = pattern.matcher(content03);

        if (matcher.matches()) {
            System.out.println("true");
            System.out.println("整体匹配=" + matcher.group(0));
            System.out.println("协议=" + matcher.group(1));
            System.out.println("域名=" + matcher.group(2));
            System.out.println("端口=" + matcher.group(3));
            System.out.println("文件=" + matcher.group(4));
        } else {
            System.out.println("false");
        }
    }
}

  1. 0-9 ↩︎

  2. 0-9 ↩︎


http://www.kler.cn/a/147422.html

相关文章:

  • 使用Java绘制图片边框,解决微信小程序map组件中marker与label层级关系问题,label增加外边框后显示不能置与marker上面
  • 微服务瞎写
  • 如何利用WebSockets实现高效的实时通信应用
  • 树状数组+概率论,ABC380G - Another Shuffle Window
  • 接上篇-使用 element-plus 优化UI界面
  • 【已解决】git push一直提示输入用户名及密码、fatal: Could not read from remote repository的问题
  • 查看linux处理器架构(uname命令 使用指南)
  • Java Elasticsearch 指标聚合
  • web项目中数据库创建流程框架
  • 掌握高效性能测试技能:JMeter基础入门!
  • C#中openFileDialog控件的使用方法
  • ubuntu22.04 arrch64版操作系统编译zlmediakit
  • 处理器及微控制器:XCZU15EG-2FFVC900I 可编程单元
  • 用于图像分类任务的经典神经网络综述
  • cpu飙高问题,案例分析(二)——批处理数据过大引起的应用服务CPU飙高
  • 个人财务管理软件CheckBook Pro mac中文版特点介绍
  • WebGL技术框架及功能
  • 【密码学引论】序列密码
  • 2-Python与设计模式--工厂类相关模式
  • 曝光!WPS用户信息或被盗用,紧急行动,迅软DSE数据加密应时而动!
  • Spring不再支持Java8了
  • 基于OGG实现MySQL实时同步
  • c#数据库:vs2022 加入mysql数据源
  • Vue基础入门(四):Vue3快速开发模板
  • http协议补充
  • 【Linux】 file命令使用