密码特殊字符包括哪些(密码必须含有特殊字符)

在平时开发时,经常会有格式要求的判断,比如密码格式要求:

长度为6-16个字符

字母(不分大小写)或数字或特殊字符(*、$、@、!、#、?)至少包含其中2种

面对这样的一个判断要求,我们该如何实现呢?本文给出不使用正则和使用正则表达式两种解决方法,其中掌握正则的套路步骤可以较好的理解,去应用不同的场景。

1、非正则实现

思路

1、判断字符串是否为空

2、判断长度

3、定义三个变量,判断对应的字符是否找到

int alphabeticFound = 0; int digitalFound = 0; int specialCharFound = 0;

依次判断字符是否满足字母、数字或者特殊字符。如满足符合要求的字符,则相关变量赋值为1;如不符合则直接返回false,表示出现不符合要求的字符。

4、判断三个变量找到的情况,累加大于1,则表示至少满足2种字符

代码实现

import java.util.Arrays;import java.util.List;public class PasswordValidateExample { //特殊字符列表 private static final List<Character> SPECIAL_CHARS = Arrays.asList(‘_’,’*’,’@’,’!’,’#’,’%’,’?’,’$’); public static boolean isMatched1(String value) { if(value == null) { return false; } //检查长度 int len = value.length(); if(len <6 ||len >16) { return false; } int alphabeticFound = 0; int digitalFound = 0; int specialCharFound = 0; for(char c: value.toCharArray()) { if(Character.isAlphabetic(c)) { alphabeticFound = 1; }else if (Character.isDigit(c)) { digitalFound = 1; }else if(SPECIAL_CHARS.contains(c)) { specialCharFound = 1; } else { //不符合要求的字符 return false; } } return (alphabeticFound digitalFound specialCharFound) > 1; }}

代码测试

import java.util.Arrays;import java.util.List;import org.junit.Assert;import org.junit.Test;public class PasswordValidateExampleTest { // 不合规则的密码 private static final List<String> INVALID_PWDS = Arrays.asList(“123”, “abc”, “###”, “123456”, “abcABC”, “123ab”, “ab12%”, “123456789012345678”, “1234567890abcdefg”, “1234567890abcd*#$”); // 符合规则的密码 private static final List<String> VALID_PWDS = Arrays.asList(“123abc”, “abc@$%”, “12ab$a”, “123456#%”, “abcABC%”, “1234567890abc@@”, “1234567890abcAbc”, “1234567890abc%*@”); @Test public void testIsMatched1_invalid() { for (String invalidValue : INVALID_PWDS) { Assert.assertFalse(PasswordValidateExample.isMatched1(invalidValue)); } } @Test public void testIsMatched1_valid() { for (String validValue : VALID_PWDS) { Assert.assertTrue(PasswordValidateExample.isMatched1(validValue)); } }}

使用junit跑一下,执行通过

密码特殊字符包括哪些(密码必须含有特殊字符)

至此,一个简单的非正则判断就写好了。接下来我们来看一下使用正则如何去完成。

2、正则表达式实现

准备

在给出最终正则表达式之前,我们先尝试给出只要符合一种以上字符即可的场景。

纯数字的正则表达式

^[0-9]*$或者^[\\d]*$//限定长度6-16^[0-9]{6,16}$或者^[\\d]{6,16}$

纯字母的正则表达式

^[A-Za-z]*$//限定长度6-16^[A-Za-z]{6,16}$

纯特殊字符的正则表达式

^[_*@!#%?$]*$//限定长度6-16^[_*@!#%?$]{6,16}$

数字、字母、特殊字符只要满足一种的

^[0-9A-Za-z_*@!#%?$]*$或者^[\\dA-Za-z_*@!#%?$]*$//限定长度6-16^[0-9A-Za-z_*@!#%?$]{6,16}$或者^[\\dA-Za-z_*@!#%?$]{6,16}$

思路

既然最终的目标至少2种组合,那么,我们写正则表达式只要将只有一种情况的情况排除即可。也就是:

1、排除纯数字的情况2、排除纯字母的情况3、排除纯特殊字符的情况//使用排除的方法我们可以使用?!来完成

步骤

1、排除纯数字的情况

(?![0-9] $)或者(?![\\d] $)

2、排除纯字母的情况

(?![A-Za-z] $)

3、排除纯特殊字符的情况

(?![_*@!#%?$] $)

4、合法字符

有了步骤#1、#2和#3的条件,我们已经把只有一种的情况排除在外,那么符合条件的字符肯定包含2种及其2种以上的情况。合法字符如下:

[0-9A-Za-z_*@!#%?$]{6,16}或者[\\dA-Za-z_*@!#%?$]{6,16}

5、最终成型

最后我们只要把上述正则连接起来,并加上开始^和结束$标记即可。

^(?![0-9] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[0-9A-Za-z_*@!#%?$]{6,16}$或者^(?![\\d] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[\\dA-Za-z_*@!#%?$]{6,16}$

程序实现

补充isMatched2和isMatched3方法。

import java.util.Arrays;import java.util.List;public class PasswordValidateExample { //特殊字符列表 private static final List<Character> SPECIAL_CHARS = Arrays.asList(‘_’,’*’,’@’,’!’,’#’,’%’,’?’,’$’); private static final String REGEX_1 = “^(?![0-9] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[0-9A-Za-z_*@!#%?$]{6,16}$”; //与REGEX_1等价,只是用\\d来替换了0-9 private static final String REGEX_2 = “^(?![\\d] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[\\dA-Za-z_*@!#%?$]{6,16}$”; public static boolean isMatched2(String value) { return isMatched(value,REGEX_1 ); } public static boolean isMatched3(String value) { return isMatched(value,REGEX_2 ); } public static boolean isMatched(String value, String regex) { return value == null ? false : value.matches(regex); } public static boolean isMatched1(String value) { if(value == null) { return false; } //检查长度 int len = value.length(); if(len <6 ||len >16) { return false; } int alphabeticFound = 0; int digitalFound = 0; int specialCharFound = 0; for(char c: value.toCharArray()) { if(Character.isAlphabetic(c)) { alphabeticFound = 1; }else if (Character.isDigit(c)) { digitalFound = 1; }else if(SPECIAL_CHARS.contains(c)) { specialCharFound = 1; } else { //不符合要求的字符 return false; } } return (alphabeticFound digitalFound specialCharFound) > 1; }}

代码测试

补充isMatched2和isMatched3的测试方法。

import java.util.Arrays;import java.util.List;import org.junit.Assert;import org.junit.Test;public class PasswordValidateExampleTest { // 不合规则的密码 private static final List<String> INVALID_PWDS = Arrays.asList(“123”, “abc”, “###”, “123456”, “abcABC”, “123ab”, “ab12%”, “123456789012345678”, “1234567890abcdefg”, “1234567890abcd*#$”); // 符合规则的密码 private static final List<String> VALID_PWDS = Arrays.asList(“123abc”, “abc@$%”, “12ab$a”, “123456#%”, “abcABC%”, “1234567890abc@@”, “1234567890abcAbc”, “1234567890abc%*@”); @Test public void testIsMatched1_invalid() { for (String invalidValue : INVALID_PWDS) { Assert.assertFalse(PasswordValidateExample.isMatched1(invalidValue)); } } @Test public void testIsMatched1_valid() { for (String validValue : VALID_PWDS) { Assert.assertTrue(PasswordValidateExample.isMatched1(validValue)); } } @Test public void testIsMatched2_invalid() { for (String invalidValue : INVALID_PWDS) { Assert.assertFalse(PasswordValidateExample.isMatched2(invalidValue)); } } @Test public void testIsMatched2_valid() { for (String validValue : VALID_PWDS) { Assert.assertTrue(PasswordValidateExample.isMatched2(validValue)); } } @Test public void testIsMatched3_invalid() { for (String invalidValue : INVALID_PWDS) { Assert.assertFalse(PasswordValidateExample.isMatched3(invalidValue)); } } @Test public void testIsMatched3_valid() { for (String validValue : VALID_PWDS) { Assert.assertTrue(PasswordValidateExample.isMatched3(validValue)); } }}

使用junit跑一下,执行通过

至此,开头提到的密码格式要求的判断就完成了。

密码格式要求:

长度为6-16个字符

字母(不分大小写)或数字或特殊字符(*、$、@、!、#、?)至少包含其中2种

3、套路回顾和扩展

套路步骤回顾

针对多种字符组合的判断,就是按照排除法的套路出牌,3个步骤即可。

先写出不符合的情况,拼接在一起再写出合法字符的情况最后加个开始^和结束$标记串联起来即可

1、排除纯数字的情况

(?![0-9] $)或者(?![\\d] $)

2、排除纯字母的情况

(?![A-Za-z] $)

3、排除纯特殊字符的情况

(?![_*@!#%?$] $)

4、合法字符

有了步骤#1、#2和#3的条件,我们已经把只有一种的情况排除在外,那么符合条件的字符肯定包含2种及其2种以上的情况。合法字符如下:

[0-9A-Za-z_*@!#%?$]{6,16}或者[\\dA-Za-z_*@!#%?$]{6,16}

5、最终成型

最后我们只要把上述正则连接起来,并加上开始^和结束$标记即可。

^(?![0-9] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[0-9A-Za-z_*@!#%?$]{6,16}$或者^(?![\\d] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[\\dA-Za-z_*@!#%?$]{6,16}$

写法变形

针对多个(?!xxxx)(?!xxxx),我们也可以使用符号|连接做一个变形,如:

^(?!^([0-9] |[A-Za-z] |[_*@!#%?$] )$)[0-9A-Za-z_*@!#%?$]{6,16}$或者^(?!^([\\d] |[A-Za-z] |[_*@!#%?$] )$)[0-9A-Za-z_*@!#%?$]{6,16}$

同样,我们补充方法isMatched4和isMatched5,并补充测试方法如下:

//变形 private static final String REGEX_3 = “^(?!^([0-9] |[A-Za-z] |[_*@!#%?$] )$)[0-9A-Za-z_*@!#%?$]{6,16}$”; private static final String REGEX_4 = “^(?!^([\\d] |[A-Za-z] |[_*@!#%?$] )$)[0-9A-Za-z_*@!#%?$]{6,16}$”; public static boolean isMatched4(String value) { return isMatched(value,REGEX_3 ); } public static boolean isMatched5(String value) { return isMatched(value,REGEX_4 ); }

测试一下

@Test public void testIsMatched4_invalid() { for (String invalidValue : INVALID_PWDS) { Assert.assertFalse(PasswordValidateExample.isMatched4(invalidValue)); } } @Test public void testIsMatched4_valid() { for (String validValue : VALID_PWDS) { Assert.assertTrue(PasswordValidateExample.isMatched4(validValue)); } } @Test public void testIsMatched5_invalid() { for (String invalidValue : INVALID_PWDS) { Assert.assertFalse(PasswordValidateExample.isMatched5(invalidValue)); } } @Test public void testIsMatched5_valid() { for (String validValue : VALID_PWDS) { Assert.assertTrue(PasswordValidateExample.isMatched5(validValue)); } }

同样case执行成功

扩展

所以,针对上述的需求,我们的正则表达式可以写如下几种:

^(?![0-9] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[0-9A-Za-z_*@!#%?$]{6,16}$或者^(?![\\d] $)(?![A-Za-z] $)(?![_*@!#%?$] $)[\\dA-Za-z_*@!#%?$]{6,16}$或者^(?!^([0-9] |[A-Za-z] |[_*@!#%?$] )$)[0-9A-Za-z_*@!#%?$]{6,16}$或者^(?!^([\\d] |[A-Za-z] |[_*@!#%?$] )$)[0-9A-Za-z_*@!#%?$]{6,16}$

通过前面的说明,想必大家对这种条件的正则已经有较好的理解了。

最后再来套用步骤练习一下,

密码格式要求调整下:

长度为6-16个字符

字母(不分大小写)或数字或特殊字符(*、$、@、!、#、?)3种都要包含

请先思考一下,再看答案

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

|

一个参考答案的步骤如下:

1、排除纯只包含数字字母的情况

(?![0-9A-Za-z] $)

2、排除纯只包含数字特殊字符的情况

(?![0-9_*@!#%?$] $)

3、排除只包含字母特殊字符的情况

(?![A-Za-z_*@!#%?$] $)

4、合法字符

有了步骤#1、#2和#3的条件,我们已经将如下几种情况排除

只包含数字

只包含字母

只包含特殊字符

只包含数字和字母

只包含数字和特殊字符

只包含字母和特殊字符

剩下只要写上合法字符情况,有了前面的排除条件,其必然都包含数字、字母和特殊字符。

[0-9A-Za-z_*@!#%?$]{6,16} 或者 [\\dA-Za-z_*@!#%?$]{6,16}

5、最终成型

最后我们只要把上述正则连接起来,并加上开始^和结束$标记即可。

^(?![0-9A-Za-z] $)(?![0-9_*@!#%?$] $)(?![A-Za-z_*@!#%?$] $)[0-9A-Za-z_*@!#%?$]{6,16}$或者[\\dA-Za-z_*@!#%?$]{6,16}

你学会了吗?

当然,还可以增加难度,比如支持中文;至少2种、3种或者全包含。有兴趣的读者可以按照上述套路尝试一下。有套路,不怕变形。

发表评论

登录后才能评论