【JAVA入门】Day20 - 正则表达式

news2025/1/10 22:26:15

【JAVA入门】Day20 - 正则表达式


文章目录

  • 【JAVA入门】Day20 - 正则表达式
    • 一、正则表达式使用的注意事项
      • 1.1 一个 [ ] 匹配一个字符
      • 1.2 表示“或者”的表达式可以再用一个 [ ] 括起来
      • 1.3 &&表示“而且”
      • 1.4 ^表示“非”
    • 二、预定义字符(只能匹配一个字符)
      • 2.1 转义字符
      • 2.2 . 表示任意字符
      • 2.3 \d 表示任意一位数字
      • 2.4 \w 表示只能是一位单词字符 [a-zA-Z_0-9]
    • 三、数量词
    • 四、正则表达式的使用
    • 五、正则表达式中用到的符号
    • 六、爬虫
      • 6.1 爬取本地信息
      • 6.2 爬取网络里的数据
    • 七、使用正则表达式进行带条件的爬取
    • 八、贪婪爬取和非贪婪爬取
    • 九、正则表达式在字符串方法中的使用
    • 十、分组
      • 10.1 捕获分组
      • 10.2 非捕获分组


        正则表达式可以校验字符串是否满足一定的规则,并用来校验数据格式的合法性。利用正则表达式校验字符串,可以省去大量代码。

package Regex;

public class RegexDemo1 {
    public static void main(String[] args) {
        /* 假如现在要求校验一个QQ号码是否正确。
    规则:6位至20位以内,0不能在开头,必须全部是数字
     */
        String qq = "1234567890";

        //利用方法
        boolean result1 = checkQQ(qq);

        //利用正则表达式
        boolean result2 = qq.matches("[1-9]\\d{5,19}");

        System.out.println(result1);
        System.out.println(result2);
    }

    public static boolean checkQQ(String qq) {
        //先把异常数据过滤,剩下的就是满足要求的数据
        int len = qq.length();
        if(len < 6 || len > 20) {
            return false;
        }

        if(qq.startsWith("0")) {
            return false;
        }

        for (int i = 0; i < qq.length(); i++) {
            char c = qq.charAt(i);
            if(c < '0' || c > '9') {
                return false;
            }
        }
        return true;
    }
}

        正则表达式的作用主要有两点:

  • 作用一:校验字符串是否满足规则。
  • 作用二:在一段文本中查找满足要求的内容。

        正则表达式的使用规则比较复杂,可以参考下面的图片:
在这里插入图片描述

一、正则表达式使用的注意事项

1.1 一个 [ ] 匹配一个字符

        需要注意的是,一个[ ]内部只能匹配一个字符:

System.out.println("ab".matches("[abc]"));			//false
System.out.println("ab".matches("[abc][abc]"));		//true

        一个中括号只能管得了一个字符,它们是逐个字符匹配的。若想匹配多个字符,就要写多个中括号。

System.out.println("aa".matches("[a-zA-Z]"));				//false
System.out.println("aa".matches("[a-zA-Z][a-zA-Z]"));		//true

1.2 表示“或者”的表达式可以再用一个 [ ] 括起来

        为了增强可读性,二者写法等价,表示 “或者”:

System.out.println("a".matches("[a-dm-p]"));			//true
System.out.println("a".matches("[a-d[m-p]]"));			//true

1.3 &&表示“而且”

        如果想求两个范围的交集,一定要写两个 & 。否则会被识别为单个’&'符号。

System.out.println("a".matches("[a-z&&[def]]"));          //false
System.out.println("e".matches("[a-z&&[def]]"));          //true
System.out.println("&".matches("[a-z&[def]]"));           //true    &被识别为单个符号

1.4 ^表示“非”

        ^bc,表示除了bc。 ^m-p 表示除了m到p。

System.out.println("a".matches("[a-z&&[^bc]]"));    //true
System.out.println("b".matches("[a-z&&[^bc]]"));    //false  等同于[ad-z]
System.out.println("a".matches("[a-z&&[^m-p]]"));   //true
System.out.println("m".matches("[a-z&&[^m-p]]"));   //false	 等同于[a-lq-z]

二、预定义字符(只能匹配一个字符)

.				任何字符
\d				一个数字:[0-9]
\D				一个非数字:[^0-9]
\s				一个空白字符:[\t\n\x0B\f\r]
\S				一个非空白字符[^\s]
\w				英文、数字、下划线[a-zA-Z_0-9]
\W				一个非单词字符[^\w]

2.1 转义字符

\ 				是一个转义字符,用来改变后面跟的那个字符原本的含义
System.out.println("\"");			//"
System.out.println("\\");			//\

2.2 . 表示任意字符

System.out.println("你".matches("."));		//true
System.out.println("你a".matches(".."));	//true

2.3 \d 表示任意一位数字

        注意:\d 才是表示任意一位数字,在字符串中需要先用 双杠 把 \ 转换为其本来的意思。

System.out.println("a".matches("\\d"));				//false
System.out.println("3".matches("\\d"));				//true
System.out.println("333".matches("\\d"));			//false
System.out.println("333".matches("\\d\\d\\d"));		//true

2.4 \w 表示只能是一位单词字符 [a-zA-Z_0-9]

System.out.println("_".matches("\\w"));				//true
System.out.println("你".matches("\\w"));			//false
System.out.println("2".matches("\\w"));				//true

三、数量词

        如果想要让一个正则表达式出现多次,可以用数量词修饰。
在这里插入图片描述

//必须是数字、字母、下划线,至少6位
System.out.println("2442fsfsf".matches("\\w{6,}"));     //true   \w表示必须是数字、字母、下划线,{6,}表示至少有6个字符
System.out.println("244f".matches("\\w{6,}"));          //false

//必须是数字和字符,必须是4位
System.out.println("23dF".matches("[a-zA-Z0-9]{4}"));   //true
System.out.println("23_F".matches("[a-zA-Z0-9]{4}"));   //false
System.out.println("23dF".matches("[\\w&&[^_]]{4}"));   //true
System.out.println("23_F".matches("[\\w&&[^_]]{4}"));   //false

四、正则表达式的使用

【练习1】需求:利用正则表达式,验证用户输入的:手机号、邮箱号、电话号码,是否满足要求。

package Regex;

public class RegexDemo3 {
    public static void main(String[] args) {
        /*
            验证手机号码      13112345678     13712345667
            验证座机电话号码    020-2324242  02122442  027-32323
            验证邮箱号码      3232323@qq.com     zhangsna@itcast.cnn
         */

        //心得:
        //拿着一个正确的数据,从左到右依次去写
        //13112345678
        String regex1 = "1[3-9]\\d{9}";         //  \d{9}表示任意数字可以出现9次,也只能出现9次

        //座机号码
        //020-2324242   02122442    0712-3242434
        //一:区号,开头是0,\d{2,3}表示任意的数字,且必须出现2~3次
        //二:-,可以出现,也可以不出现,但出现至多只有一次,因此是零次或一次
        //三:号码,不能以0开头,从第二位开始可以是任意数字。号码的总长度:5~10位
        String regex2 = "0\\d{2,3}-?[1-9]\\d{4,9}";


        //邮箱号码
        //3232323@qq.com    zhangsna@itcast.cnn     dlei0009@163.com    dlei0009@pci.com.cn
        //第一部分:@的左边,至少出现一次,即一次或多次
        //第二部分:@,只能出现一次
        //第三部分A:    .的左边,可以是字母或数字,但是没有下划线,大概有2~6位
        //第三部分B:    .
        //第三部分C:    .的右边,大写字母和小写字母都可以,只能出现2~3次
        //第三部分D:    pci.com.cn这里出现了多次.XXX,可以把.com和.cn看成一组.XXX结构出现了两次
        String regex3 = "\\w+@[\\w&&[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2}";
        
    }
}

【练习2】24小时的正则表达式。

//00:00:00
//12:20:30
//第一个:前
//第一位是0或1时,此时第二位可以是任意数字
//中间用“或”
//第一位是2时,此时第二位只能是0~3
//第二个:前
//分钟的第一位可以是0~5,第二位可以是任意数字
//第二个:后
//秒钟的第一位可以是0~5,第二位可以是任意数字
String regex4 = "([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
//可以用()分组优化掉后面的分钟和秒钟,直接出现两次
String regex5 = "([01]\\d|2[0-3])(:[0-5]\\d){2}";

【练习3】写用户名和身份证的正则表达式。

 /*
        验证用户名是否满足要求:大小写字母,数字,下划线一共4-16位
        验证身份证号码是否满足要求。
        简单要求:18位,前17位任意数字,最后一位可以是大小写的X。
        复杂要求:按照身份证号码的格式严格要求。
         */
        //用户名
        String regex6 = "\\w{4,16}";

        //身份证号码的简单校验:身份证号一共18位
        //第一位一定不是0,是1~9
        //之后16位都是任意数字
        //最后一位可以是大小写的X
        String regex7 = "[1-9]\\d{16}(X|x|\\d)";
        String regex8 = "[1-9]\\d{16}[\\dXx]";
        String regex8_1 = "[1-9]\\d{16}(\\d|(?i)x)";

        //忽略大小写的书写方式
        //在匹配的时候,忽略abc的大小写
        String regex9 = "(?i)abc";
        //在匹配的时候,忽略bc的大小写
        String regex10 = "a(?i)bc";
        //在匹配的时候,忽略b的大小写
        String regex11 = "a((?i)b)c";

        //复杂身份证的检验
        //410801 1993 02 28 457x
        //前6位:省份,市区,派出所等信息,第一位不是0,后5位是任意数字
        //年的前半段:18 19 20
        //年的后半段:任意数字*2
        //月份: 01 ~ 09 10 11 12
        //日期: 01 ~ 09 10 ~ 19 20 ~ 29 30 ~ 31
        //后四位: 任意数字出现3次 最后一位可以是数字,可以是大小写X
        String regex12 = "[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}(\\d|(?i)x)";
        System.out.println("41080119930228457x".matches(regex12));

        这里出现了一种新的正则,表示忽略大小写,用(?i)表示,他放在谁前面,就表示忽略后面字符的大小写。关于类似的正则还有很多,没法介绍全,可以查看API手册。

五、正则表达式中用到的符号

在这里插入图片描述
在这里插入图片描述

        注意方括号和圆括号的区分,方括号表示里面的内容出现一次,永远是单个字符;圆括号表示里面的内容进行分组,和数学运算里的含义类似。
        还要注意“且”要用两个&表示;“或”用一个|表示,表示并集,如果写在方括号里面,可以省略;“非”用^表示。

六、爬虫

        正则表达式另一个作用是,在一段文本中查找满足要求的内容,这就是爬虫的概念。

6.1 爬取本地信息

        如下,我们利用 正则表达式 Pattern 和 文本匹配器 Matcher 找到了所有 JavaXX 格式的文本子串。

public class Spider {
    public static void main(String[] args) {
        String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会" +
                "逐渐登上历史舞台";

        //1.获取正则表达式的对象
        Pattern p = Pattern.compile("Java\\d{0,2}");
        //2.获取一个文本匹配器
        Matcher m = p.matcher(str);
        //3.利用循环读取
        while(m.find()) {
            String s = m.group();
            System.out.println(s);
        }
    }

6.2 爬取网络里的数据

        爬取网络中的数据,需要用URL对象连接网页,然后用一个BufferedReader对象去逐行读取。之后针对每行按照正则表达式使用Matcher匹配出想要的内容即可。

package Regex;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Spider2 {
    public static void main(String[] args) throws IOException {
        /*
        把链接:https://www.leuai.cn/idcard/
        中所有的身份证号码爬取出来。
         */

        //创建一个URL对象
        URL url = new URL("https://www.leuai.cn/idcard/");

        //连接上这个网址
        URLConnection conn = url.openConnection();

        //创建一个对象去读取网络中的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

        //创建一个正则表达式对象
        String regex = "[1-9]\\d{17}";
        Pattern pattern = Pattern.compile(regex);

        String line;
        //在读取的时候每次读一整行
        while((line = br.readLine()) != null) {
            //对每一行进行文本匹配
            Matcher matcher = pattern.matcher(line);
            //使用matcher找到所有满足身份证格式的子串
            while(matcher.find()){
                System.out.println(matcher.group());
            }
        }
        br.close();
    }
}

【练习】利用正则表达式爬取文本中的座机号码、邮箱、手机号、热线号码。

package Regex;

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

public class RegexDemo4 {
    public static void main(String[] args) {
        /*
        手机号:18512516758     18512508907
        邮箱:boniu@itcast.cn
        座机电话:01036517895    010-98951256
        邮箱:bozai@itcast.cn
        热线电话:400-618-9090   400-618-4000    4006184000  4006189090
        手机号正则:1[3-9]\d{9}
        邮箱正则:\w+@[\w&&[^_]]{2,6}(\.[a-zA-Z]{2,3}){1,2}
        座机电话:0\d{2,3}-?[1-9]\d{4,9}
        热线电话:400-?[1-9]\\d{2}-?[1-9]\\d{3}
         */

        String s = " 手机号:18512516758     18512508907\n" +
                "        邮箱:boniu@itcast.cn\n" +
                "        座机电话:01036517895    010-98951256\n" +
                "        邮箱:bozai@itcast.cn\n" +
                "        热线电话:400-618-9090   400-618-4000    4006184000  4006189090";

        String regex = "(1[3-9]\\d{9})|(\\w+@[\\w&&[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2})|(0\\d{2,3}-?[1-9]\\d{4,9})|(400-?[1-9]\\\\d{2}-?[1-9]\\\\d{3})";

        //1.获取正则表达式对象
        Pattern p = Pattern.compile(regex);

        //2.获取Matcher对象
        Matcher m = p.matcher(s);

        //3.逐行匹配
        while(m.find()){
            System.out.println(m.group());
        }
    }
}

七、使用正则表达式进行带条件的爬取

        使用正则表达式爬取数据时,我们有时需要一些限制条件。

package Regex;

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

public class RegexDemo5 {
    public static void main(String[] args) {
        /*
        Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来
        不久Java17也会逐渐登上历史舞台
         */
        /*
        需求1:爬取版本号为8,11,17的Java文本,但是只要Java,不显示版本号。
        需求2:爬取版本号为8,11,17的Java文本。正确爬取结果为:Java8 Java11 Java17 Java17。
        需求3:爬取除了版本号为8,11,17的Java文本。正确爬取结果为:Java。
         */
        String s = "java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和JAva11,因为这两个是长期支持版本,下一个长期支持版本是JAVa17,相信在未来\n" +
                "        不久JAVA17也会逐渐登上历史舞台";

        //需求1.定义正则表达式
        //?是占位符,理解为前面的数据Java
        //=表示在Java后面要跟随的数据要满足的要求
        //但是在获取的时候,只获取前半部分
        String regex1 = "((?i)java)(?=8|11|17)";

        //需求2.加上这些数字
        //?是占位符,理解为前面的数据Java
        //:表示在Java后面要跟随的数据要满足的要求
        //但是在获取的时候,也带上后半部分
        String regex2 = "((?i)java)(?:8|11|17)";

        //需求3.选取第一个不带版本号的java
        //?是占位符,理解为前面的数据Java
        //!表示在Java后面要跟随的数据要满足的要求,但是这个!表示不要,意思是"不要"后面有这些要求的内容
        String regex3 = "((?i)java)(?!8|11|17)";

        //1.获取正则表达式对象
        Pattern p = Pattern.compile(regex1);

        //2.获取Matcher对象
        Matcher m = p.matcher(s);

        //3.逐行匹配
        while(m.find()){
            System.out.println(m.group());
        }

    }
}

        ?作为占位符,指代前面的"java",?后面的符号决定了以什么条件爬取。

  • ?= 爬取满足后面“条件”的子串,但是获取时不获取等号后面的“条件”
  • ?: 爬取满足后面“条件”的子串,而且获取时也带上后面的“条件”
  • ?! 爬取不满足后面“条件”的子串,获取时不带上后面的“条件”

八、贪婪爬取和非贪婪爬取

        这是两种不同的爬取策略。

    /*
        Java自从95年问世以来,abbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaa
        经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来
        不久Java17也会逐渐登上历史舞台
         */

        需求1:按照ab+的方式爬取ab,b尽可能多获取。
        需求2:按照ab+的方式爬取ab,b尽可能少获取。
        解释:ab+表示a出现1次,b出现1次或多次,b可以只出现1次,也可以全部出现。
        贪婪爬取:abbbbbbbbbbbb。
        非贪婪爬取:ab。
        在 Java 当中,默认的就是贪婪爬取,如果我们在数量词 + * 的后面加上问号,此时就是非贪婪爬取。

package Regex;

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

public class RegexDemo6 {
    public static void main(String[] args) {
            /*
        Java自从95年问世以来,abbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaa
        经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来
        不久Java17也会逐渐登上历史舞台
         */
    /*
        只写+和*表示贪婪爬取
        +?  非贪婪爬取
        *?  非贪婪爬取
     */

        String s = " Java自从95年问世以来,abbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
                "        经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来\n" +
                "        不久Java17也会逐渐登上历史舞台";

        //贪婪爬取,+表示1次或多次
        String regex1 = "ab+";
        Pattern p = Pattern.compile(regex1);
        Matcher m = p.matcher(s);

        while(m.find()) {
            System.out.println(m.group());		//abbbbbbbbbbbb
        }

        //非贪婪爬取
        String regex2 = "ab+?";
        Pattern pattern = Pattern.compile(regex2);
        Matcher matcher = pattern.matcher(s);

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

九、正则表达式在字符串方法中的使用

        String 类中还有几个正则表达式的相关方法:

方法名说明
public boolean matches(String regex)判断字符串是否满足正则表达式的规则
public String replaceAll(String regex,String newStr按照正则表达式的规则进行替换
public String[] split(String regex)按照正则表达式的规则切割字符串

【练习】使用以上方法操作字符串。

package Regex;

public class RegexDemo7 {
    public static void main(String[] args) {
            /*
    有一段字符串:小诗诗dqwefqwfqwfwq12312小丹丹dqwefqwfqwfwq12312小惠惠
    要求1:把字符串中三个姓名之间的字母替换为vs。
    要求2:把字符串中的三个姓名切割出来。
     */

        String s = "小诗诗dqwefqwfqwfwq12312小丹丹dqwefqwfqwfwq12312小惠惠";

        String regex = "[\\w&&[^_]]+";

        //把满足正则表达式的内容替换为vs
        String result1 = s.replaceAll(regex,"vs");
        System.out.println(result1);

        //利用正则表达式作为分隔符,切割字符串
        String[] result2 = s.split(regex);
        for(int i = 0; i < result2.length; i++) {
            System.out.println(result2[i]);
        }
    }
}

十、分组

        正则表达式中的分组刚才已经介绍过,其实就是小括号。
        由于有“或”、“且”等逻辑符号的存在,分组在正则表达式中的编写是必须存在的,否则去掉括号的话下面的正则表达式就会改变原意(或的范围变化)。

String regex = "[1-9]\\d{16}(\\d|X|x)";

        分组的另一个用途则是可以简化代码。

//24小时制的正则表达式
String regex1 = "([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
String regex2 = "([01]\\d|2[0-3]):([0-5]\\d){2}";

        正则表达式中的分组,其实是有组号的,也就是分组的序号,规则如下:

  • 规则1:从1开始,连续不间断。
  • 规则2:以左括号为基准,最左边的左括号是第一组,其次为第二组,以此类推。
(\\d+)(\\d+)(\\d+)
//第一组 第二组 第三组

(\\d+(\\d+))(\\d+)
//第一组 第二组 第三组

        分组编号的意义在于捕获。

10.1 捕获分组

        捕获分组就是把这一组的数据捕获出来,再用一次。看下面的例子。

【练习】需求1:判断一个字符串的开始和结束字符是否一致?只考虑一个字符。

a123a b456b 17891 &abc&

需求2:判断一个字符串的开始部分和结束部分的多个字符是否一致。

abc123abc b456b 123789123 &!@abc&!@

需求3:判断一个字符串的开始部分和结束部分是否一致?开始部分内部每个字符也需要一致。

aaa123aaa bbb456bbb 111789111 &&abc&!

package Regex;

public class RegexDemo8 {
    public static void main(String[] args) {
        //需求1:判断一个字符串的开始和结束字符是否一致?只考虑一个字符。
        //  \\组号,表示吧第X组的内容拿出来,再用一次
        String regex1 = "(.).+\\1";
        System.out.println("a123a".matches(regex1));
        System.out.println("b456b".matches(regex1));
        System.out.println("17891".matches(regex1));
        System.out.println("&abc&".matches(regex1));

        //需求2:判断一个字符串的开始部分和结束部分的多个字符是否一致。
        //abc123abc b456b 123789123 &!@abc&!@
        String regex2 = "(.+).+\\1";
        System.out.println("abc123abc".matches(regex2));
        System.out.println("b456b".matches(regex2));
        System.out.println("123789123".matches(regex2));
        System.out.println("&!@abc&!@".matches(regex2));

        //需求3:判断一个字符串的开始部分和结束部分是否一致?开始部分内部每个字符也需要一致。
        //*表示0次或多次
        //(.)把首字母看作一组,\\2表示把首字母拿出来再次使用
        // \\2*表示把第一组反复出现0次或多次
        //aaa123aaa bbb456bbb 111789111 &&abc&!
        String regex3 = "((.)\\2*).+\\1";
        System.out.println("aaa123aaa".matches(regex3));
        System.out.println("bbb456bbb".matches(regex3));
        System.out.println("111789111".matches(regex3));
        System.out.println("&&abc&!".matches(regex3));

        后续还要使用本组的内容,可以使用这两个符号:

正则内部使用:\\组号
正则外部使用:$组号

        利用分组,我们可以把重复的冗余字段替换为单个字段。

package Regex;

public class RegexDemo9 {
    public static void main(String[] args) {
        //将字符串:我要学学编编编编程程程程程程
        //替换为:我要学编程
        String str = "我要学学编编编编程程程程程程";

        //把重复的内容替换为单个的
        //学学 学      编编编编 编      程程程程程程 程
        //(.) 表示把重复内容的第一个字符看作一组
        // \\1+ 表示第一个字符再次出现,1次或多次
        // $1 表示把正则表达式中第一组的内容再拿出来用一次
        //由于是在正则表达式外部,所以要用$符号
        String result = str.replaceAll("(.)\\1+", "$1");
        System.out.println(result);
    }
}

10.2 非捕获分组

        有的时候,我们在分组之后不再需要使用本组数据,仅仅是把数据括起来,这时候可以用这些符号。
在这里插入图片描述
        标注非捕获分组的时候,小括号不占用组号。

package Regex;

public class RegexDemo10 {
    public static void main(String[] args) {
        //身份证号码简易正则表达式
        //如果只是仅仅想把这组数据括起来,而不是想要继续使用括号里面的数据
        //可以用?:标注小括号
        //特点:不占用组号
        String regex = "[1-9]\\d{16}(?:\\d|X|x)\\1";  // 报错,不知道第一组是谁

        //(?=) (?!) 也是非捕获分组,但是一般情况使用(?:)

        System.out.println("41080119930228547x".matches(regex));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2040572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PCB结构

覆铜板&#xff08;Copper Clad Laminate&#xff0c;CCL&#xff09;是PCB&#xff08;Printed Circuit Board&#xff0c;印制电路板&#xff09;的主体&#xff0c;由基材和覆在其表面上的一层铜箔组成&#xff0c;基材通常是由增强材料&#xff08;如玻璃纤维织物&#xff…

Qt 系统相关 - 事件

目录 1. 事件介绍 2. 事件的处理 示例1&#xff1a;处理鼠标进入和离开 示例2&#xff1a;当鼠标点击时&#xff0c;获取对应的坐标值&#xff1b; 3. 按键事件 3.1 单个按键 3.2 组合按键 4. 鼠标事件 4.1 鼠标单击事件 4.2 鼠标释放事件 4.3 鼠标双击事件 4.4 鼠标…

一篇文章了解上位机软件架构

软件架构 上位机基本软件架构**UI层****业务层&#xff08;承上启下&#xff09;****驱动层** 上位机基本软件架构 基本上所有软件都可以分为三层结构进行设计&#xff0c;ui界面层&#xff0c;中间业务逻辑层&#xff0c;驱动层&#xff0c;各个层级之间相互联系&#xff0c;…

汇编编译环境的安装

目录 1. 下载安装包 1.1 迅雷下载链接 1.2 Gitee下载 2. 安装 1. 下载安装包 1.1 迅雷下载链接 迅雷云盘迅雷云盘https://pan.xunlei.com/s/VO4AFFTT3ls2zGSOvFOLSP_mA1?pwdkmeh# 1.2 Gitee下载 assembler language: assembler languagehttps://gitee.com/Axurea/asse…

软考高级:数据库设计中,属性冲突、命名冲突、结构冲突

在数据库设计中&#xff0c;属性冲突、命名冲突和结构冲突是常见的问题&#xff0c;它们主要涉及不同数据源或表之间的数据整合和管理。下面我们通过通俗易懂的例子和解释来理解这些概念。 通俗示例 想象你有两家书店&#xff0c;它们各自维护一份图书的库存记录。 属性冲突…

高质量翻译对中国开发者提高游戏用户参与度的影响

随着中国游戏开发商继续向全球市场扩张&#xff0c;用户参与度成为其游戏成功的关键因素。在竞争激烈的行业中&#xff0c;玩家有无数选择可供选择&#xff0c;保持用户参与对于维持游戏的流行和增长至关重要。高质量的翻译在这一过程中起着至关重要的作用&#xff0c;确保游戏…

动力电池制造行业RFID产品应用方案

在全球能源转型的大背景下&#xff0c;新能源汽车产业蓬勃发展&#xff0c;动力电池作为其核心部件&#xff0c;其性能和质量至关重要。然而&#xff0c;当前国内上百家动力电池生产企业在自动化和信息化方面存在诸多不足&#xff0c;严重制约了行业的发展。实现动力电池的智能…

邦德创意研发的果皮咖啡,让喝咖啡也能有喝奶茶的满足感

在当下咖啡饮品市场中&#xff0c;果咖早已不是新鲜事物。它们以各式各样的水果与咖啡的融合&#xff0c;为咖啡爱好者带来新鲜的味觉体验。然而&#xff0c;很多果咖饮品虽色彩斑斓、风味独特&#xff0c;却往往止步于水果和咖啡的直接混合&#xff0c;未能触及更深层次的健康…

使用 onBeforeRouteLeave 组合式函数提升应用的用户体验

title: 使用 onBeforeRouteLeave 组合式函数提升应用的用户体验 date: 2024/8/14 updated: 2024/8/14 author: cmdragon excerpt: 摘要&#xff1a;本文介绍了在Nuxtjs中使用onBeforeRouteLeave组合式函数来提升应用用户体验的方法。onBeforeRouteLeave允许在组件离开当前路…

IDEA 创建类时自动生成注释

一、背景 在开发的过程中&#xff0c;公司都会要求开发针对自己创建的类进行一些描述说明&#xff0c;为了便于程序员在创建类时快速生成注释。 二、如何配置? 打开File -> Settings -> Editor -> File and Code Templates -> Includes&#xff0c;在File Header…

JavaWeb04-MyBatis与Spring结合

目录 前言 一、MyBatis入门&#xff08;MyBatis官网&#xff09; 1.1 创建mybatis项目&#xff08;使用spring项目整合式方法&#xff09; 1.2 JDBC 1.3 数据库连接池 1.4 实用工具&#xff1a;Lombok 二、MyBatis基础操作 2.1 准备工作 2.2 导入项目并实现操作 2.3 具…

LeetCode 热题 HOT 100 (036/100)【宇宙最简单版】【创作中】

希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#xff01;

Ubuntu(22.04)云主机SSH安全加固

1、新增SSH服务端口 #vim /etc/ssh/sshd_config 找到 #Port 22 去掉注释符&#xff0c;下面添加&#xff1a;Port [新端口] 2、本地防火墙放通 #ufw allow [新端口] #ufw reload //防火墙重新加载 #ufw status verbose //查询是否开放SSH新端口 3、腾讯云防火墙配…

在线预约小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;在线预约管理&#xff0c;管理员管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;在线预约&#xff0c;我的 开发系统&#xff1a;Windows 架构模…

为何UDP攻击相比常规攻击更易导致服务器瘫痪?

在网络安全领域&#xff0c;UDP&#xff08;用户数据报协议&#xff09;攻击因其独特的特性和高效的破坏性而备受关注。与常规的网络攻击相比&#xff0c;UDP攻击往往能够更快地使目标服务器陷入瘫痪状态&#xff0c;这背后的原因值得我们深入探讨。 UDP协议的无连接性是其成为…

Linux--HTTP协议(http服务器构建)

目录 1.HTTP 协议 2.认识 URL 3.urlencode 和 urldecode&#xff08;编码&#xff09; urlencode&#xff08;URL编码&#xff09; urldecode&#xff08;URL解码&#xff09; 4.HTTP 协议请求与响应格式 4.1HTTP 常见方法&#xff08;三种&#xff09; 5.HTTP 的状态码…

node速起架子

链接&#xff1a;https://pan.baidu.com/s/1NF1e75P8pNDzphO1jBUSyg 提取码&#xff1a;sf3w 下载node 安装好node -v 配置npm的全局安装路径 使用管理员身份运行命令行&#xff0c;在命令行中&#xff0c;执行如下指令&#xff1a; npm config set prefix "E:\develop\…

【网络】TCP协议通信的重要策略——滑动窗口,快重传,流量控制,拥塞控制,延时应答

目录 MSS值 滑动窗口 滑动窗口与重发机制 快重传机制 滑动窗口与流量控制 滑动窗口与拥塞控制 延时应答 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 相关文章 【网络】传输层TCP协议的报头和传输机制-CSDN博客 【网络】详解TCP协议通信时客户/服务端的状态-CSDN博…

「MyBatis」数据库相关操作2

&#x1f387;个人主页 &#x1f387;所属专栏&#xff1a;Spring &#x1f387;欢迎点赞收藏加关注哦&#xff01; #{} 和 ${} 我们前面都是采用 #{} 对参数进行赋值&#xff0c;实际上也可以用 ${} 客户端发送⼀条 SQL 给服务器后&#xff0c;大致流程如下&#xff1a; 1.…

图像识别,图片线条检测

import cv2 import numpy as np # 读取图片 img cv2.imread(1.png)# 灰度化 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 边缘检测 edges cv2.Canny(gray, 100, 200) 当某个像素点的梯度强度低于 threshold1 时&#xff0c;该像素点被认为是非边缘&#xff1b;当梯度强度…