java中正则表达式的使用

匹配规则

匹配规则如下:详细可参照菜鸟教程正则视频教程韩顺平正则表达式专题。注意Java中用 \\ 进行正则匹配。

几点注意事项:

        ^和$的使用,例如:Pattern.compile("[1-9]{6}")和Pattern.compile("^[1-9]{6}$")都是匹配连续6个1-9之间的数字,但是不同的是使用^和$匹配的字符串不能包含其它字符。例如:对于字符串 "123456abc",Pattern.compile("[1-9]{6}")会匹配成功,因为它包含了6个从1到9之间的数字。而 Pattern.compile("^[1-9]{6}$") 会匹配失败,因为这个字符串不仅仅包含6个数字,还有其他字符。

反向引用

        反向引用可以理解为复制了一份前面捕获组捕获的字符串,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用 \\分组号,外部反向引用$分组号。例如下列实例代码中的(\\d)\\1{2}表示:捕获一个数字,并引用这个捕获组两次,也就是说会匹配三个重复的数字。

public void Test(){
        String content = "12321-111222333";
        //String content2 = "12321-333333333";
        Pattern compile = Pattern.compile("\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}");
        Matcher matcher = compile.matcher(content);
        while (matcher.find()){
            // 12321-111222333
            System.out.println(matcher.group(0));
        }
    }

常用函数说明

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class RegexMatches
{
    public static void main( String[] args ){
 
      // 按指定模式在字符串查找
      String line = "This order was placed for QT3000! OK?";
      String pattern = "(\\D*)(\\d+)(.*)";
 
      // 创建 Pattern 对象
      Pattern r = Pattern.compile(pattern);
 
      // 现在创建 matcher 对象
      Matcher m = r.matcher(line);
      if (m.find( )) {
         System.out.println("Found value: " + m.group(0) );
         System.out.println("Found value: " + m.group(1) );
         System.out.println("Found value: " + m.group(2) );
         System.out.println("Found value: " + m.group(3) ); 
      } else {
         System.out.println("NO MATCH");
      }
   }
}

Matcher类

find()方法

  1. 根据指定的规则,定位满足规则的子字符串
  2. 找到后,将子字符串的开始的索引记录到 matcher对象的属性 int[] groups;开始索引记录到groups[0],把该子字符串的结束的索引+1的值记录到 groups[1]
  3. 同时记录oldLast的值为子字符串的结束的索引+1的值,即下次执行find时,就从此开始匹配

group()方法

        如下图是goup()对应的源码,通过返回语句我们可以看到进行了一步字符串截取,如果是group(0)则返回的是group(0)到group(1)对应的值的字符串,即把按照规则匹配的字符串截取出来,例如group(0)=a, group(1)=b,则截取的字符串位置为[a, b)。这也是为什么group(1)存储的是匹配字符串结束索引+1。

         

        对于用括号 ( ) 分组的正则匹配,例如下列示例代码中的匹配规则Pattern.compile("(\\d\\d)(\\d\\d)");匹配的是连续4位数字,但是我们将匹配规则分为了两组,通过下图的debug可以看到group(0)=0,group(1)=4,那么调用Matcher中的group(0)方法得到的就是content内容中[0, 4)的数据,即“2024”。而group(2)=0,group(3)=2表示第一个分组(\\d\\d)匹配到的内容,即“20”,group(4)=2,group(5)=4表示第二个分组(\\d\\d)匹配到的内容,即“24”.所以调用matcher.group(1)方法返回的结果是20,matcher.group(2)返回的结果是24.【注意,参照上图的group()方法源码,别把group参数和Matcher中的group()方法搞混了】

        总结一下:matcher.group(0)得到的就是匹配到的字符串,如果对应的正则表达式有多个括号()分组,比如示例为2组,则matcher.group(1)是第一个分组匹配到的字符,matcher.group(2)是第二个分组匹配到的字符串。

public void Test(){
        String content = "2024年4月25日,神舟十八号载人飞船发射取得圆满成功。";
        Pattern compile = Pattern.compile("(\\d\\d)(\\d\\d)");
        Matcher matcher = compile.matcher(content);
        while (matcher.find()){
            System.out.println(matcher.group(0)); //2024
            System.out.println(matcher.group(1)); //20
            System.out.println(matcher.group(2)); //24
        }
    }

索引方法

public void Test(){
        String content = "2024年4月25日,神舟十八号载人飞船发射取得圆满成功。";
        Pattern compile = Pattern.compile("\\d\\d\\d\\d");
        Matcher matcher = compile.matcher(content);
        while (matcher.find()){
            System.out.println(matcher.group(0)); //2024
            System.out.println(matcher.start()); //0
            System.out.println(matcher.end()); //4
        }
    }

 replaceAll()方法

        根据模式匹配的字符串全部替换为replaceAll()参数中的字符串,返回替换后的新字符串。

public void Test(){
        String content = "2024年4月25日,神舟十八号载人飞船发射取得圆满成功。2024";
        Pattern compile = Pattern.compile("2024");
        Matcher matcher = compile.matcher(content);
        String newContent = matcher.replaceAll("二零二四");
        //二零二四年4月25日,神舟十八号载人飞船发射取得圆满成功。二零二四
        System.out.println(newContent);
    }

        在字符串中也有replaceAll()方法,方法参数可以是正则表达式,下面是一个算法题示例。需要注意的是,replaceAll()方法可以结合正则匹配以及反向引用,但是正则表达式需要使用括号 () 括起来,因为这样表示一个捕获组,然后结合反向引用解决实际问题。

public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String input = in.next();
        String output = input.replaceAll("(\\d+)", "*$1*");
        System.out.println(output);
    }

replaceFirst()方法

        和replaceAll()类似,只不过replaceFirst()只会替换第一个满足要求的字符串,返回值依然是替换后的字符串。

public void Test(){
        String content = "2024年4月25日,神舟十八号载人飞船发射取得圆满成功。2024";
        Pattern compile = Pattern.compile("2024");
        Matcher matcher = compile.matcher(content);
        String newContent = matcher.replaceFirst("二零二四");
        //二零二四年4月25日,神舟十八号载人飞船发射取得圆满成功。2024
        System.out.println(newContent);
    }

Pattern类

matches()方法

        整体匹配,返回的是一个boolean值,一般用于校验用户输入的数据是否合法,不加^和$限定也默认是这种匹配模式。boolean flag = Pattern.matches("^13|14|15|18\\d{9}$", content);

        String字符串中也有对应的matches()方法,参数是正则匹配规则,返回boolean值。示例如下:

public static void main(String[] args) {
        String input = "13696581731";
        boolean flag = input.matches("13\\d{9}");
        System.out.println(flag); //true
    }

 案例

1.简单的邮箱格式验证

public static void main(String[] args) {
        String input = "qianjin1920@qq.com";
        boolean mailNotify = input.matches(".+@.+\\.com");
        if (mailNotify){
            System.out.println("邮箱验证成功");
        }else {
            System.out.println("验证失败");
        }
    }

2.验证一个数是否是整数或小数

public static void main(String[] args) {
        String num1 = "0.5";
        if (num1.matches("[-+]?[1-9]\\d*|0\\.\\d+")){
            System.out.println("yes");
        }else {
            System.out.println("No");
        }
    }

3.网址解析

public static void main(String[] args) {
        String url = "http://www.sohu.com:8080/abc/index.htm";
        Matcher matcher = Pattern.compile("([a-z]+)://(www\\.[a-z]+\\.[a-z]+):(\\d+)[\\w-/]*/([\\w.]+)").matcher(url);
        while (matcher.find()){
            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));
        }
    }

运行结果如下:

4.密码等级校验

 密码按如下规则进行计分,并根据不同的得分为密码进行安全等级划分。

一、密码长度:

  • 5 分: 小于等于4 个字符
  • 10 分: 5 到7 字符
  • 25 分: 大于等于8 个字符


二、字母:

  • 0 分: 没有字母
  • 10 分: 密码里的字母全都是小(大)写字母
  • 20 分: 密码里的字母符合”大小写混合“


三、数字:

  • 0 分: 没有数字
  • 10 分: 1 个数字
  • 20 分: 大于1 个数字


四、符号:

  • 0 分: 没有符号
  • 10 分: 1 个符号
  • 25 分: 大于1 个符号


五、奖励(只能选符合最多的那一种奖励):

  • 2 分: 字母和数字
  • 3 分: 字母、数字和符号
  • 5 分: 大小写字母、数字和符号

最后的评分标准:

  • >= 90: 非常安全
  • >= 80: 安全(Secure)
  • >= 70: 非常强
  • >= 60: 强(Strong)
  • >= 50: 一般(Average)
  • >= 25: 弱(Weak)
  • >= 0:  非常弱(Very_Weak)


对应输出为:

  • VERY_SECURE
  • SECURE
  • VERY_STRONG
  • STRONG
  • AVERAGE
  • WEAK
  • VERY_WEAK

请根据输入的密码字符串,进行安全评定。
注:
字母:a-z, A-Z
数字:0-9
符号包含如下: (ASCII码表可以在UltraEdit的菜单view->ASCII Table查看)
!"#$%&'()*+,-./     (ASCII码:0x21~0x2F)
:;<=>?@             (ASCII码:0x3A~0x40)
[\]^_`              (ASCII码:0x5B~0x60)
{|}~                (ASCII码:0x7B~0x7E)

输入描述:

输入一个string的密码

输出描述:

输出密码等级

public class HWTest {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String pwd = in.nextLine();
        int score = 0;
        //奖励标志位,分别表示大写字母,小写字母,数字,符号
        int[] reward = {0, 0, 0, 0};
        // 长度
        if (pwd.length() >= 8){
            score += 25;
        }else if (pwd.length() >= 5){
            score += 10;
        }else{
            score += 5;
        }
        System.out.println("长度+" + score);
        // 字母
        Matcher matcher = Pattern.compile("(?=.*[a-z])(?=.*[A-Z])").matcher(pwd);
        Matcher matcher1 = Pattern.compile("[a-z]+|[A-Z]+").matcher(pwd);
        if (matcher.find()){ //字母大小混合
            score += 20;
            reward[0] = reward[1] = 1;
        }else if (matcher1.find()){ //只有大写字母或者小写字母
            score += 10;
            reward[0] = 1; //只有大写或者小写字母时计大写字母标志位为1
        } //没有字母不加分
        System.out.println("字母+" + score);

        //数字
        Matcher matcher2 = Pattern.compile("\\d").matcher(pwd);
        int count = 0;
        while (matcher2.find()){
            count++;
        }
        if (count == 1){ // 只有1个数字
            score += 10;
            reward[2] = 1;
        }else if(count > 1){ //多个数字
            score += 20;
            reward[2] = 1;
        }
        System.out.println("数字+" + score);

        //符号
        String regex = "[!\"#$%&'()*+,-./:;<=>?@\\[\\]^_`{|}~]";
        Matcher matcher3 = Pattern.compile(regex).matcher(pwd);
        count = 0;
        while (matcher3.find()){
            count++;
        }
        if (count == 1){ // 只有1个符号
            score += 10;
            reward[3] = 1;
        }else if(count > 1){ //多个符号
            score += 25;
            reward[3] = 1;
        }
        System.out.println("符号+" + score);

        //奖励
        if (reward[0] == 1 && reward[1] == 1 && reward[2] == 1 && reward[3] == 1){
            score += 5;
        }else if (reward[0] == 1 && reward[2] == 1 && reward[3] == 1){
            score += 3;
        }else if (reward[0] == 1 && reward[2] == 1){
            score += 2;
        }
        System.out.println("奖励+" + score);

        if (score >= 90){
            System.out.println("VERY_SECURE");
        }else if (score >= 80){
            System.out.println("SECURE");
        }else if (score >= 70){
            System.out.println("VERY_STRONG");
        }else if (score >= 60){
            System.out.println("STRONG");
        }else if (score >= 50){
            System.out.println("AVERAGE");
        }else if (score >= 25){
            System.out.println("WEAK");
        }else {
            System.out.println("VERY_WEAK");
        }
        System.out.println("总得分:" + score);
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值