巧用正则化,让你判定算法如日登天!!!

正则化菜鸟教程(比较详细)

正则表达式 – 教程 | 菜鸟教程 (runoob.com)

正则化

        正则化是一种用来描述、匹配和操作字符串的强大工具。他是代码中尤为重要的一部分,是做比较时常用的手段。下面是一些常见的正则表达式元字符和用法:

符号        用法
.匹配任意单个字符(除了换行符)。
*匹配前面的元素零次或多次。
+匹配前面的元素一次或多次。
?匹配前面的元素零次或一次。
[ ]定义一个字符集,匹配其中的任意一个字符。
[ ^ ]否定的字符集,匹配未列出的任意一个字符。
( )标记一个子表达式的开始和结束位置。
|用于在两个或多个模式之间进行选择。
\用来转义特殊字符,使其具有普通字符的含义。

常见的正则表达式示例:

  • .*:匹配任意长度的字符序列。
  • [0-9]:匹配任意一个数字。
  • [a-zA-Z]:匹配任意一个字母(包括大小写)。
  • \d:匹配任意一个数字,等效于[0-9]
  • \w:匹配任意一个单词字符(字母、数字或下划线),等效于[a-zA-Z0-9_]
  • \s:匹配任意一个空白字符(空格、制表符、换行符等)。

正则化举例

例题:某网站引入了新的密码强度检测功能,以提高用户账户的安全性,用户设置密码时,系统会根据密码的复杂度给予相应的评级。

密码强度法则如下: 弱密码:密码长度大于等于8个字符,至少包含种类: 大写字母,小写字母、数字里的2种;

中等密码:密码长度大于等于8个字符,至少包含种类:大写字母、小写字母、数字里的2种,必须包含特殊字符 (!$@%&*)

强密码: 密码长度大于等于8个字符,且必须包含大写字母、小写字母、数字和特殊字符。 密码不合法:不满足上述条件

现在你需要写一段java程序判断用户输入的密码评级。

输入描述:键盘输入第一行输入用例个数n,接下来的n行每一行输入一个待检测的密码串。

输出描述:输出n行,每一行输出对应密码的评级,弱密码输出weak,中等密码输出medium ,强密码输出strong,不合法输出error。 密码不合法: 不满足上述条件的。

题中,需要我们判断输入密码是否包含有数字、大小写字母以及特殊符号,包含一个或多个。按照这个题的想法,我们首先需要密码大于8字符,其次需要先判断是否有特殊字符,如果没有则判断弱密码规则,如果有则判断时中等还是强密码即可。

下面是代码(代码是自己写的,可能不够完美,也不是最简短的,有更好的可以自己写):

import java.util.Scanner;

public class HHH {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        for (int i = 0; i < n; i++) {
            String password = scanner.nextLine();
            String strength;
            int count = 0;
            if (password.length() < 8) {
                strength = "error";
            } else if (containF(password)) { 
                if (containB(password) && containS(password) && containD(password)) {
                    strength = "strong";
                } else if ((containB(password) && containD(password)) || (containS(password) && containD(password)) || (containS(password) && containB(password))) {
                    strength = "medium";
                } else {
                    strength = "error";
                }
            } else if ((containS(password) && containB(password)) || (containS(password) && containD(password)) || (containD(password) && containB(password))) {
                strength = "weak";
            } else {
                strength = "error";
            }
            System.out.println(strength);
        }


    }
    
    // 是否包含字符
    public static boolean containF(String s) {
        return s.matches(".*[!$@%&*].*");
    }
    // 是否包含大写字母
    public static boolean containB(String s) {
        return s.matches(".*[A-Z].*");
    }
    // 是否包含小写字母
    public static boolean containS(String s) {
        return s.matches(".*[a-z].*");
    }
    // 是否包含数字
    public static boolean containD(String s) {
        return s.matches(".*\\d.*");
    }
}

        这里我每一个都是单独判断的,可以保证字符判断不受符号位置的影响。这句话是什么意思呢?也就是说在使用正则表达式的时候,我们如果写一个很长的正则表达式,则我们字符串上的相匹配字符的顺序必须和表达式顺序相同。可能还是有很多童鞋不太明白什么意思,下面我举个例子具体说明一下。
        首先我们写一段正则表达式,并输出:

        String a = "AsBB";
        String b = "aBcdef";
        String c = "A";
        String regex = "[A-Z]";
        System.out.print(a.matches(regex)+"\t");
        System.out.print(b.matches(regex)+"\t");
        System.out.print(c.matches(regex)+"\t");

//false    false    true

        上面代码输出结果应该是什么呢?准确答案是false false true。可以看出,正则表达式中一个"[]"只会匹配一个位置,且从第一个位置开始匹配。

        如果想让上述a和c变成true,我们就可以加上.*这个特殊的符号,

        String a = "AsBB";
        String b = "aBcdef";
        String c = "A";
        String regex = "[A-Z].*";
        System.out.print(a.matches(regex)+"\t");
        System.out.print(b.matches(regex)+"\t");
        System.out.print(c.matches(regex)+"\t");

//true	false	true

它表示可以匹配它后面的0个或者多个多个,比如:[A-Z].*,表达的意思就是只要字符串中只要第一个是大写字母就算匹配成功。所以b还是false,因为b开头并不是大写字母。
        那我们怎么匹配b呢,还是一样,只要我们将条件改成.*[A-Z].*,就表示只要匹配到大写字母,不管前面有什么,也不管后面有什么。简言之就是不管在什么位置的大写字母即可。
 

        String a = "AsBB";
        String b = "aBcdef";
        String c = "A";
        String regex = ".*[A-Z].*";
        System.out.print(a.matches(regex)+"\t");
        System.out.print(b.matches(regex)+"\t");
        System.out.print(c.matches(regex)+"\t");

//true	true	true	

好,现在我们通过.*解决了匹配位置的问题,但是真的解决了吗?回到主题,刚才所说的位置问题还是存在的,如果我想判断一个字符串中既有大写又有小写,该如何写?相信你们很快就有了答案,.*[A-Z].*[a-z].*注:上述写法等同于.*[A-Z].*.*[a-z].*,这样写有问题吗?我们来看下面这个例子

        String a = "AsBB";
        String b = "aBcdef";
        String c = "A";
        String d = "aaaaaB";

        String regex = ".*[A-Z].*[a-z].*";
        System.out.print(a.matches(regex)+"\t");
        System.out.print(b.matches(regex)+"\t");
        System.out.print(c.matches(regex)+"\t");
        System.out.print(d.matches(regex)+"\t");

//true	true	false	false

从例子可以看出,我的c字符串因为只有大写报了false,但是新添加的d为什么也是false,这就是在说的最主要的问题,也就是位置的影响,因为我们的正则化语句的位置关系是大写在前,小写在后,他只能匹配这种位置关系的字符串以至于只有[小写字母,大写字母]这种结构无法被匹配。

当然对于这个问题我们可以写这样的语句:

(.*[A-Z].*[a-z].*)|(.*[a-z].*[A-Z].*)

用括号将两个语句包裹,通过"|"来进行或运算,就可以完成操作,不过这样,如果不是规定的位置明确的关系,远不如用if语句单独进行判断来的更加准确也就是如下:
 


        String d = "aaaaaB";

        System.out.println(d.matches(".*[A-Z].*") && d.matches(".*[a-z].*"));

//true

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值