Java正则表达式_java 正则表达式的底层实现-程序员宅基地

技术标签: 正则表达式  正则  

正则表达式底层实现

1、不考虑分组

代码示例

public static void main(String args[]){
    
    String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。" +
            "2001年9月24日,J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升,与J2SE1.3相比," +
            "其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、安全套接字(Socket)支持(通过SSL与TLS协议)、" +
            "全新的I/OAPI、正则表达式、日志与断言。2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
            "J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布1.0版本以来的最重大的更新,其中包括泛型支持、" +
            "基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";

    // \\d代表一个任意的数字,这段正则匹配的是一个四位的数字
    String regStr = "\\d\\d\\d\\d";
    // 创建模式对象,即正则表达式对象
    Pattern pattern = Pattern.compile(regStr);
	// 创建匹配器,按照正则表达式的规则匹配content字符串
    Matcher matcher = pattern.matcher(content);

    while (matcher.find()) {
    
        System.out.println(matcher.group(0));
    }
}

代码解析

①、matcher.find()
  1. 根据指定的规则,定位满足规则的子字符串(比如content中的第一个匹配结果2000)

  2. 找到后,将子字符串的开始、结束索引记录到matcher对象的属性 int[] groups 中

    groups[0] = 0; 记录的为子字符串开始索引

    groups[1] = 4; 记录的为子字符串结束索引 + 1

  3. 同时记录oldLast的值为子字符串结束索引 + 1,下次执行matcher.find()时,就从oldLast开始匹配

②、matcher.group(0)
// 源码
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();
}

根据groups[0] = 0 和 groups[1] = 4的记录的位置,从content开始截取字符串返回,就是[0,4),左闭右合,包含索引为0的值,但不包含索引为4的值

2、考虑分组

什么是分组,比如 (\d\d)(\d\d),正则表达式中有(),表示分组,第1个()表示第1组,第2个()表示第2组

代码示例

public static void main(String args[]){
    
    String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。" +
            "2001年9月24日,J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升,与J2SE1.3相比," +
            "其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、安全套接字(Socket)支持(通过SSL与TLS协议)、" +
            "全新的I/OAPI、正则表达式、日志与断言。2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
            "J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布1.0版本以来的最重大的更新,其中包括泛型支持、" +
            "基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";

    String regStr = "(\\d\\d)(\\d\\d)";
    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(2));
    }
}

代码解析

①、matcher.find()
  1. 根据指定的规则,定位满足规则的子字符串(比如content中的第一个匹配结果2000)

  2. 找到后,将子字符串的开始、结束索引记录到matcher对象的属性 int[] groups 中

    1. groups[0] = 0; 记录的为子字符串开始索引 groups[1] = 4; 记录的为子字符串结束索引 + 1
    2. 记录第1组()匹配到的字符串groups[2] = 0; groups[3] = 2;
    3. 记录第2组()匹配到的字符串groups[4] = 2; groups[5] = 4;
    4. 更多的分组…
  3. 同时记录oldLast的值为子字符串结束索引 + 1,下次执行matcher.find()时,就从oldLast开始匹配

②、matcher.group()
  1. group(0):表示匹配到的子字符串
  2. group(1):表示匹配到的子字符串的第1组子串
  3. group(2):表示匹配到的子字符串的第2组子串
  4. 更多的分组…

正则表达式语法

元字符

转义符 \\

使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错。

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

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

字符匹配符

符号 含义 示例 说明 匹配输入
[ ] 可接收的字符列表 [efgh] e、f、g、h的任意1个字符 e、f、g、h
[^] 不接收的字符列表 [^abc] 除a、b、c之外的任意1个字符,包括数字和特殊符号 1、2、$
- 连字符 A-Z 任意单个大写字母 A
. 匹配除\n以外的任何字符 a…b 以a开头,b结尾,中间包括2个任意字符的字符串 aaab、aefb、a36b、a#*b
\\d 匹配单个数字字符,相当于[0-9] \\d{3}(\\d)? 包含3个或4个数字的字符串 123、4567
\\D 匹配单个非数字字符,相当于[^0-9] \\D(\\d)* 以单个非数字字符开头,后接任意个数字符串 a、A342
\\w 匹配单个数字、大小写字母字符、下划线,相当于[0-9a-zA-z] \\d{3}\\w{4} 以3个数字字符开头的长度为7的数字字母字符串 123abcd、12345Pe
\\W 匹配单个非数字、大小写字符字符,相当于[^0-9a-zA-Z] \\W+\\d{2} 以至少1个非数字字母字符开头,2个数字字符结尾的字符串 #29、#?@10
\\s 匹配任何空白字符(空格,制表符等)
\\S 匹配任何非空白字符

Java正则表达式默认是区分字母大小写的,如何实现不区分大小写?

  • (?i)abc:表示abc都不区分大小写
  • a(?i)bc:表示bc不区分大小写
  • a((?i)b)c:表示只有b不区分大小写
  • Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE):表示匹配不区分字母大小写

选择匹配符 |

符号 含义 示例 匹配输入
| 匹配 | 之前或之后的表达式 ab|cd ab、cd

限定符

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

符号 含义 示例 说明 匹配输入
* 指定字符重复0次或n次(无要求)零到多 (abc)* 仅包含任意个abc的字符串 abc、abcabcabc
+ 指定字符重复1次或n次(至少一次)一到多 m+(abc)* 以至少1个m开头,后接任意个abc的字符 m、mabc、mabcabc
? 指定字符重复0次或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

非贪婪匹配:当?紧随其他限定符(*、+、?、{n}、{n,}、{n.m})之后,匹配模式是非贪婪匹配,会匹配尽可能短的字符串,而默认的贪婪匹配会匹配尽可能长的字符串。

定位符

定位符规定要匹配的字符串出现的位置,比如在字符串的开始还是结束的位置

符号 含义 示例 说明 匹配输入
^ 指定起始字符 ^[0-9]+[a-z]* 以至少一个数字开头,后接任意个小写字符的字符串 123、123abc
$ 指定结束字符 ^[0-9]\-[a-z]+$ 以一个数字开头,后接连字符-,并以至少一个小写字母结尾的字符串 1-a
\\b 匹配目标字符串的边界 han\\b 这里说的是字符串的边界指的是子串间有空格,或者是目标字符串的结束位置 sphan
\\B 匹配目标字符串的非边界 han\\B 和\\b的含义刚刚相反 hanshunping

分组

捕获分组

分组构造形式 说明
(pattern) 非命名捕获,捕获匹配的子字符串,编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号
(?pattern) 命名捕获,将匹配的子字符串捕获到一个组名或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?‘name’)
public static void main(String[] args) {
    

    // 1、非命名捕获
    String content = "秦朝(前221年—前207年),是中国历史上第一个统一的封建王朝";
    String regStr = "(\\d\\d)(\\d)";

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

    while (matcher.find()) {
    
        System.out.println(matcher.group(0));
        System.out.println("\t分组1:" + matcher.group(1));
        System.out.println("\t分组2:" + matcher.group(2));
    }
}
public static void main(String[] args) {
    

    // 2、命名捕获
    String content = "秦朝(前221年—前207年),是中国历史上第一个统一的封建王朝";
    String regStr = "(?<g1>\\d\\d)(?<g2>\\d)";

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

    while (matcher.find()) {
    
        System.out.println(matcher.group(0));
        System.out.println("\t分组1:" + matcher.group(1));
        System.out.println("\t分组1:" + matcher.group("g1"));
        System.out.println("\t分组2:" + matcher.group(2));
        System.out.println("\t分组2:" + matcher.group("g2"));
    }
}

非捕获分组

分组构造形式 说明
(?:pattern) 匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用“or”字符(|)组合模式部件的情况很有用,例如,'industr(?:y|ies)'是比’industry|industries’更经济的表达式
(?=pattern) 它是一个非捕获匹配。例如,'Windows(?=95|NT|2000)'匹配’Windows 2000’中的"Windows",但不匹配"Windows 3.1"中的"Windows"
(?!pattern) 该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串,它是一个非捕获匹配。例如,“Windows(?!95|98|NT|2000)“匹配"Windows 3.1"中的"Windows”,但不匹配"Windows 2000"中的"Windows”
public static void main(String[] args) {
    

    // 1、(?:pattern)
    String content = "迪迦奥特曼,戴拿奥特曼,盖亚奥特曼,阿古茹奥特曼";
    // 等效于(迪迦奥特曼|戴拿奥特曼|盖亚奥特曼|阿古茹奥特曼)
//        String regStr = "(迪迦奥特曼|戴拿奥特曼|盖亚奥特曼|阿古茹奥特曼)";
    String regStr = "(?:迪迦|戴拿|盖亚|阿古茹)奥特曼";

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

    while (matcher.find()) {
    
        System.out.println(matcher.group(0));
    }

}
public static void main(String[] args) {
    

	// 2、(?=pattern) 零宽正向先行断言
    String content = "奥特曼迪迦,奥特曼戴拿,奥特曼盖亚,奥特曼阿古茹";
    String regStr = "奥特曼(?=迪迦|戴拿|盖亚|阿古茹)";

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

    while (matcher.find()) {
    
        System.out.println(matcher.group(0));
    }

}
public static void main(String[] args) {
    

    // 3、(?!pattern) 负向先行断言
    String content = "奥特曼迪迦,奥特曼戴拿,奥特曼盖亚,奥特曼阿古茹";
    String regStr = "奥特曼(?!阿古茹)";

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

    while (matcher.find()) {
    
        System.out.println(matcher.group(0));
    }

}

正则表达式三个常用类

java.util.regex包主要包括以下三个类

  • Pattern

    Pattern对象是一个正则表达式对象。Pattern类没有公共构造方法。要创建一个Pattern对象需要调用其公共静态方法compile,它返回一个Pattern对象,该方法接收一个正则表达式作为它的参数。

    比如:Pattern pattern = Pattern.compile(pattern);

  • Matcher

    Matcher对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共构造方法,需要调用Pattern对象的matcher方法来获得一个Matcher对象,该方法接收一个文本内容作为其参数。

    比如:Matcher matcher = pattern.matcher(content);

  • PatternSyntaxException

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

常用方法

Pattern.matches

该方法接收两个参数,第一个参数为正则表达式,第二个参数为需要匹配的内容。用于检测字符串是否匹配给定的正则表达式。

package com.example;

import java.util.regex.Pattern;

/**
 * @Description Pattern.matches
 * @CreateTime 2024/3/22 18:11
 * @Author dyf
 */
public class PatternMethod {
    

    public static void main(String[] args) {
    

        String content = "落霞与孤鹜齐飞,秋水共长天一色";
        String regStr = ".*秋水.*";

        boolean isMatch = Pattern.matches(regStr, content);
        System.out.println("是否匹配成功: " + isMatch);

    }

}

该方法底层调用的是Matcher类的matches方法

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

Matcher类

  1. public int start():返回以前匹配的初始索引
  2. public int start(int group):返回再以前的匹配操作期间,由给定组所捕获的子序列的初始索引
  3. public int end():返回最后匹配字符之后的偏移量
  4. public int end(int group):返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量
  5. public boolean lookingAt():尝试将从区域开头开始的输入序列与该模式匹配
  6. public boolean find():尝试查找与该模式匹配的输入序列的下一个子序列
  7. public boolean find(int start):重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列
  8. public boolean matches():尝试将整个区域与模式匹配
  9. public Matcher appendReplacement(StringBuffer sb, String replacement):实现非终端添加和替换步骤
  10. public StringBuffer appendTail(StringBuffer sb):实现终端添加和替换步骤
  11. public String replaceAll(String replacement):替换模式与给定替换字符串相匹配的输入序列的每个子序列
  12. public String replaceFirst(String replacement):替换模式与给定替换字符串匹配的输入序列的第一个子序列
  13. public static String quoteReplacement(String s):返回指定字符串的字面替换字符串,这个方法返回一个字符串,就像传递给Matcher类的appendReplacement方法一个字面字符串一样工作
  14. public Matcher appendReplacement(String Buffer sb, String replacement):实现非终端添加和替换步骤

反向引用

分组捕获后,可以在后面被使用,从而编写出一个比较实用的匹配模式,称之为反向引用。这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用\\分组号,外部反向引用$分组号

案例

1、匹配两个连续的相同数字

2、匹配五个连续的相同数字

3、匹配个位与千位相同,十位与百位相同的数字

4、请在字符串中检索商品编号,形式如:12321-333999111 这样的号码,要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同

package com.example;

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

/**
 * @Description TODO
 * @CreateTime 2024/3/22 21:17
 * @Author dyf
 */
public class RegExp04 {
    

    public static void main(String[] args) {
    

        /*
          1、匹配两个连续的相同数字

          2、匹配五个连续的相同数字

          3、匹配个位与千位相同,十位与百位相同的数字
          
          4、在字符串中检索商品编号,形式如:12321-333999111 这样的号码,要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同
        */

//        String content = "11";
//        String regStr = "(\\d)\\1";

//        String content = "11111";
//        String regStr = "(\\d)\\1{4}";

//        String content = "1212";
//        String regStr = "(\\d)(\\d)\\1\\2";
        
        String content = "12321-333999111";
        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());
        }

    }

}

String类中使用正则表达式

替换功能

public String replaceAll(String regex, String replacement)

package com.example;

/**
 * @Description TODO
 * @CreateTime 2024/3/22 22:13
 * @Author dyf
 */
public class RegExp06 {
    

    public static void main(String[] args) {
    

        String content = "迪迦,戴拿,盖亚";

        content = content.replaceAll("戴拿|盖亚", "迪迦");

        System.out.println(content);

    }

}

判断功能

public boolean matches(String regex)

package com.example;

/**
 * @Description TODO
 * @CreateTime 2024/3/22 22:17
 * @Author dyf
 */
public class RegExp07 {
    

    public static void main(String[] args) {
    
        // 验证一个手机号,要求必须是以138、139开头的
        String phone = "13879450636";
        boolean matches = phone.matches("^13[89]\\d{8}");
        System.out.println(matches);
    }

}

分割功能

public String[] split(String regex)

package com.example;

/**
 * @Description TODO
 * @CreateTime 2024/3/22 22:23
 * @Author dyf
 */
public class RegExp08 {
    

    public static void main(String[] args) {
    

        // 要求按照 # 或者 - 或者 ~ 或者 数字 来分割
        String content = "hello##abc-jack12smith~北京";

        String[] split = content.split("(#|-|~|\\d)+");

        for (String s : split) {
    
            System.out.println(s);
        }

    }

}

练习

验证是否是汉字

package com.example;

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

/**
 * @Description 验证是否是汉字
 * @CreateTime 2024/3/11 15:12
 * @Author dyf
 */
public class RegExpTest01 {
    

    public static void main(String[] args) {
    

        String regStr = "^[\u4E00-\u9FA5]+$";
        String content = "秦朝建立于公元前年";

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

        if (matcher.find()) {
    
            System.out.println(matcher.group());
        }

    }

}

验证是否邮政编码

package com.example;

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

/**
 * @Description 验证是否邮政编码 要求:1-9开头的一个六位数 比如:123890
 * @CreateTime 2024/3/11 15:12
 * @Author dyf
 */
public class RegExpTest02 {
    

    public static void main(String[] args) {
    

        String regStr = "^[1-9]\\d{5}$";
        String content = "123890";

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

        if (matcher.find()) {
    
            System.out.println(matcher.group() + "符合格式");
        } else {
    
            System.out.println("不符合格式");
        }

    }

}

验证是否是QQ号码

package com.example;

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

/**
 * @Description 验证是否是QQ号码 要求:是1-9开头的一个(5位-10位数)
 * @CreateTime 2024/3/11 15:12
 * @Author dyf
 */
public class RegExpTest03 {
    

    public static void main(String[] args) {
    

        String regStr = "^[1-9]\\d{4,9}$";
        String content = "1179678168";

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

        if (matcher.find()) {
    
            System.out.println(matcher.group() + "符合格式");
        } else {
    
            System.out.println("不符合格式");
        }

    }

}

验证是否是手机号码

package com.example;

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

/**
 * @Description 验证是否是手机号码 要求:必须以13、14、15、17、18开头的11位数
 * @CreateTime 2024/3/11 15:12
 * @Author dyf
 */
public class RegExpTest04 {
    

    public static void main(String[] args) {
    

        String regStr = "^1[34578]\\d{9}$";
        String content = "12279450636";

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

        if (matcher.find()) {
    
            System.out.println(matcher.group() + "符合格式");
        } else {
    
            System.out.println("不符合格式");
        }

    }

}

验证是否是URL

package com.example;

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

/**
 * @Description 验证是否是URL
 * @CreateTime 2024/3/11 15:12
 * @Author dyf
 */
public class RegExpTest05 {
    

    public static void main(String[] args) {
    

        /**
         * 1、^((http|https)://)匹配URL开头
         * 2、([\w-]+\.)+[\w-]+匹配 www.bilibili.com
         * 3、/[\w-?/=#.&%]*$ 匹配结尾
         */
        String regStr = "^((http|https)://)([\\w-]+\\.)+[\\w-]+/[\\w-?/=#.&%]*$";
        String content = "https://njuics.github.io/OnJava8/#/book/01-What-is-an-Object?id=%e6%8a%bd%e8%b1%a1";

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

        if (matcher.find()) {
    
            System.out.println(matcher.group() + "符合格式");
        } else {
    
            System.out.println("不符合格式");
        }

    }

}

结巴程序

package com.example;

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

/**
 * @Description 结巴程序
 * @CreateTime 2024/3/22 21:52
 * @Author dyf
 */
public class RegExp05 {
    

    public static void main(String[] args) {
    

        // 把类似:"我....我要....学学学学....编程Java!" 通过正则表达式,修改成 "我要学编程Java"

        String content = "我....我要....学学学学....编程Java!";
        String regStr = "\\.";

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

        content = matcher.replaceAll("");
        System.out.println(content);

        regStr = "(.)\\1+";
        pattern = Pattern.compile(regStr);
        matcher = pattern.matcher(content);

        content = matcher.replaceAll("$1");
        System.out.println(content);

    }

}

验证电子邮件格式是否合法

package com.example;

/**
 * @Description 验证电子邮件格式是否合法
 * @CreateTime 2024/3/22 22:28
 * @Author dyf
 */
public class HomeWork01 {
    

    public static void main(String[] args) {
    

        /*
            规定电子邮件规则为:
                1、只能有一个@
                2、@前面是用户名,可以是a-z A-Z 0-9 -字符
                3、@后面是域名,并且域名只能是英文字母,比如 qq.com 或者 tsinghua.org.cn
         */

        String email = "[email protected]";
        String regxStr = "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+$";

        boolean matches = email.matches(regxStr);
        System.out.println(matches);
    }

}

验证是不是整数或者小数

package com.example;

/**
 * @Description 验证是不是整数或者小数
 * @CreateTime 2024/3/22 22:41
 * @Author dyf
 */
public class HomeWork2 {
    

    public static void main(String[] args) {
    

        // 提示:这个题要考虑正数和负数
        // 比如:123 -345 34.89 -87.9 -0.01 0.45等

        String content = "0.45";
        String regx = "^[+-]?([1-9]\\d*|0)(\\.\\d+)?$";

        System.out.println(content.matches(regx));
    }

}

解析URL

package com.example;

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

/**
 * @Description 解析URL
 * @CreateTime 2024/3/22 22:50
 * @Author dyf
 */
public class HomeWork03 {
    

    public static void main(String[] args) {
    

        /*
            https://www.bilibili.com:8080/video/index.html
            1、要求得到协议是什么  https
            2、域名是什么        www.bilibili.com
            3、端口是什么        8080
            4、文件名是什么      index.html
         */

        String content = "https://www.bilibili.com:8080/video/index.html";
        String regxStr = "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.]+)$";

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

        if (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));
        }

    }

}

常用正则表达式

一、校验数字的表达式

数字:^[0-9]*$

n位的数字:^\d{n}$

至少n位的数字:^\d{n,}$

m-n位的数字:^\d{m,n}$

零和非零开头的数字:^(0|[1-9][0-9]*)$

非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$

带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$

正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$

有两位小数的正实数:^[0-9]+(.[0-9]{2})?$

有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$

非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$

非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$

非负整数:^\d+$ 或 ^[1-9]\d*|0$

非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$

非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$

非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$

正浮点数:^[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]*))$

负浮点数:^-([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]*)))$

浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

二、校验字符的表达式

汉字:^[\u4e00-\u9fa5]{0,}$

英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$

长度为3-20的所有字符:^.{3,20}$

由26个英文字母组成的字符串:^[A-Za-z]+$

由26个大写英文字母组成的字符串:^[A-Z]+$

由26个小写英文字母组成的字符串:^[a-z]+$

由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$

由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$

中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$

中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$

可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+ 

禁止输入含有~的字符:[^~\x22]+

三、特殊需求表达式

Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$

域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?

InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$

手机号码:^(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])\d{8}$ (由于工信部放号段不定时,所以建议使用泛解析 ^([1][3,4,5,6,7,8,9])\d{9}$)

电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 

国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7} 

18位身份证号码(数字、字母x结尾):^((\d{18})|([0-9x]{18})|([0-9X]{18}))$

帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$

密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$

强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$  

日期格式:^\d{4}-\d{1,2}-\d{1,2}

一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$

一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$ 

钱的输入格式:
	1.有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$ 
	2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$ 
	3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$ 
	4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$ 
	5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$ 
	6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$ 
	7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ 
	8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ 
	备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
	
xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$

中文字符的正则表达式:[\u4e00-\u9fa5]

双字节字符:[^\x00-\xff]    (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))

空白行的正则表达式:\n\s*\r    (可以用来删除空白行)

HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? />    (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)

首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$)    (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)

腾讯QQ号:[1-9][0-9]{4,}    (腾讯QQ号从10000开始)

中国邮政编码:[1-9]\d{5}(?!\d)    (中国邮政编码为6位数字)

IP地址:\d+\.\d+\.\d+\.\d+    (提取IP地址时有用)

IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))

笔记内容来源:韩顺平老师的课程

常用正则表达式来源:https://www.cnblogs.com/zxin/archive/2013/01/26/2877765.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_46361701/article/details/135922527

智能推荐

Alcohol 120%刻录教程-程序员宅基地

文章浏览阅读261次。Alcohol 120%刻录教程 【虎.无名】由于非正版的Nero可能刻出废盘,所以我改用“Alcohol 120%”了,它不但可用来虚拟光驱,刻录功能似乎也不弱。参考:Nero刻出废盘的秘密(待考证)[url]http://zeroliu.blogdriver.com/zeroliu/..._利用alcohol 120%制作音乐cd

细数【SD-WEBUI】的模型:谁是最适合的模型&从哪里找到它们_sd模型网站-程序员宅基地

文章浏览阅读8.4k次,点赞6次,收藏27次。神奇的模型在哪儿?谁才是最适合我的模型?村口大黄狗为何连夜嚎叫?……_sd模型网站

【C# & WebService】【2】URL Http的基本使用_c#怎么用url链接-程序员宅基地

文章浏览阅读588次。学习Http的基本请求方法,在本地模拟一个web服务器_c#怎么用url链接

Unity -- animation clip 无法正常播放_clip视频播放不了-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏2次。首先说遇到的问题:animation clip文件 拖拽到某物体的Animation组件上,但是不起作用。一般操作是这样,会造成该问题:1,选中一个物体A(此时不携带Animator和Animation组件),想给他加跳跃动画;2,windows -> animation -> animation 打开animation的窗口;3,在窗口中点击“Create”,创建了一个名字为 “jump_anim”的 clip, 注意,unity同时给物体添加了Animator组件,而非A_clip视频播放不了

黑马程序员-高新技术-交通灯管理-程序员宅基地

文章浏览阅读297次。学习了张孝祥老师的交通灯项目后,就深深的喜欢上了张孝祥老师的讲课风格,他的每句话话中都显露出了他的清晰、完整、丰富、深入的思维,可以推断出他已经把这个题目理解的非常到位了。他的讲课方式很像我的高中老师,就是把一个题目从头到尾的思路一一的都讲出来,不跳跃任何一个思维点,不遗漏任何一个思维点,这才是一个智者的思路。希望黑马程序员的老师们都能像张孝祥老师一样事无巨细的把一个知识点讲透彻,讲的不遗漏。

图像线段检测几种方法_lines1, _, _, _ = lsd1.detect(gray_image1, 2, 2)-程序员宅基地

文章浏览阅读1.1k次。OpenCV-contrib有一个名为FastLineDetector的东西,如果它被用作LSD的替代品似乎很好。如果你有点感动,你会得到与LSD几乎相同的结果。当我将OpenCV提升到4.1.0时,LineSegmentDetector(LSD)消失了。_lines1, _, _, _ = lsd1.detect(gray_image1, 2, 2)

随便推点

用python和pygame写游戏_用Python和Pygame写游戏-从入门到精通(6)-程序员宅基地

文章浏览阅读138次。掌握了小小的像素,我们可以使用更加复杂一点的东西了,对,就是图像,无数的像素的集合~还记得上次我们为了生成的一张图片,花了无数时间,还好一般游戏不会在游戏的过程中动态生成图像,都是将画好的作为资源封装到游戏中。对2D游戏,图像可能就是一些背景、角色等,而3D游戏则往往是大量的贴图。虽然是基础,这里还是要罗嗦一下,之前说的RBG图像,在游戏中我们往往使用RGBA图像,这个A是alpha,也就是表示透..._pygame 中 screen.set_clip

TCP/IP协议_tcp/ip包内容-程序员宅基地

文章浏览阅读1.6k次。笔记_tcp/ip包内容

javaweb基础_创建一个savelogin.java文件,该页面作用-程序员宅基地

文章浏览阅读1.4k次。静态网站:在tomcat的webapps目录下创建一个目录(命名必须不包含中文和空格),这个目录称之为项目目录在项目目录下创建一个html文件动态网站:在tomcat的webapps目录下创建一个项目目录在项目目录下创建如下内容WEB-INF目录在WEB-INF目录下创建web.xml文件创建静态或动态页面http协议:无状态协议,仅连接一次(ftp_创建一个savelogin.java文件,该页面作用

eclipse的hibernate映射工具_eclipse映射器-程序员宅基地

文章浏览阅读310次。升级网址http://hibernatesynch.sourceforge.net/_eclipse映射器

跨境电商亚马逊erp规避跟卖自发货铺货,数据更安全_跨境erp如何保证卖家数据安全?-程序员宅基地

文章浏览阅读313次。现在越来越多的跨境电商用户想拥有一套属于自己的自发货铺货ERP系统,但是众所周知,开发一套的成本太高,而且找不到很专业的技术员去开发,那么,我们提供的ERP私有化部署,成本低,你需要的投入的是一个服务器,以及一个ERP的定制费用,我们会把ERP加密部署到你的服务器中,这样你的数据就在你的服务器中。能看到数据的只有你自己,而且你对外销售出去的账号端口,你作为上家,同样是可以看到他们的数据!不是所有的部署都可以做销售系统,一般分为个人店群卖家部署,企业店群部署,培训孵化机构部署!每一个版本的部署,权限不一样,同_跨境erp如何保证卖家数据安全?

Vue绑定数据v-bind缩写:字段名 双向绑定v-model缩写:model 监听动作v-on缩写@ 记住:与数据相关用冒号 与动作相关用@_v-model简写-程序员宅基地

文章浏览阅读1.2w次,点赞6次,收藏11次。:是v-bind缩写:数据同步v-bind指令可以用于响应式地更新 HTML 特性:<spanv-bind:title="message">@是指令v-on缩写 :动作监听v-on指令,它用于监听 DOM 事件<form v-on:submit.prevent="onSubmit">...</form>.修饰符:动作具体化修饰符 (Modifiers) 是以半角句号.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如.pr..._v-model简写