package org.example;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
// 密码 8-16位
// 只能包含字母 数字 及符号~!@#$%^&_
// 不包含用户名
// 不包含3个及以上重复、连续及键盘排序字符
public class PwdValidator {
// 允许的特殊字符
private static final String SPECIAL_CHARS = "~!@#$%^&_";
public static boolean validatePassword(String password, String username) {
// 校验长度8-16位
if (password.length() < 8 || password.length() > 16) {
System.out.println("密码长度为 8 到 16位");
return false;
}
// 只能包含字母 数字 及符号~!@#$%^&_
if (!Pattern.matches("^[a-zA-Z0-9" + Pattern.quote(SPECIAL_CHARS) + "]+$", password)) {
return false;
}
// 密码不包含用户名
// if(password.toLowerCase().contains(username.toLowerCase())) {
// System.out.println("密码不能包含用户名");
// return false;
// }
Pattern pattern = Pattern.compile(Pattern.quote(username), Pattern.CASE_INSENSITIVE);
if (pattern.matcher(password).find()) {
System.out.println("密码不能包含用户名");
return false;
}
// 不包含3个及以上重复字符
// if(hasRepeatedChars(password)){
// System.out.println("不能包含3个及以上重复字符");
// return false;
// }
if (Pattern.compile("(.)\\1{2,}").matcher(password).find()) {
System.out.println("不能包含3个及以上重复字符");
return false;
}
// 不包含3个及以上连续字符
if(hasSequentialChars(password)){
System.out.println("不能包含3个及以上连续字符");
return false;
}
// 不包含3个及以上键盘排序字符
if(hasKeyboardSequence2(password)){
System.out.println("不能包含3个及以上键盘排序字符");
return false;
}
return true;
}
private static boolean hasSequentialChars(String password) {
password = password.toLowerCase();
for (int i = 0; i < password.length() - 2; i++) {
char c1 = password.charAt(i);
char c2 = password.charAt(i + 1);
char c3 = password.charAt(i + 2);
// 检查升序连续
if (c1 + 1 == c2 && c2 + 1 == c3) {
return true;
}
// 检查降序连续
if (c1 - 1 == c2 && c2 - 1 == c3) {
return true;
}
}
return false;
}
// private static boolean hasRepeatedChars(String password) {
// for (int i = 0; i < password.length() - 2; i++) {
// char c = password.charAt(i);
// if (c == password.charAt(i + 1) && c == password.charAt(i + 2)) {
// return true;
// }
// }
// return false;
// }
//
// private static boolean hasKeyboardSequence1(String password) {
// password = password.toLowerCase();
// for (String str : KEYBOARD_SEQUENCES) {
// for (int i = 0; i < str.length() - 2; i++) {
// // 顺序
// String sequence = str.substring(i, i + 3);
// // 逆序
// String reverseSequence = new StringBuilder(sequence).reverse().toString();
//
// if (password.contains(sequence) || password.contains(reverseSequence)) {
// return true;
// }
// }
// }
// return false;
// }
private static boolean hasKeyboardSequence2(String password) {
// 定义键盘布局(Shift状态)
List<List<Character>> keyboard1 = Arrays.asList(
Arrays.asList('!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+'),
Arrays.asList('q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '|'),
Arrays.asList('a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"'),
Arrays.asList('z', 'x', 'c', 'v', 'b', 'n', 'm', '<', '>', '?')
);
// 定义键盘布局(非Shift状态)
List<List<Character>> keyboard2 = Arrays.asList(
Arrays.asList('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '='),
Arrays.asList('q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\'),
Arrays.asList('a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\''),
Arrays.asList('z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/')
);
char[] chars = password.toLowerCase().toCharArray();
int[] y = new int[chars.length]; // 行坐标
int[] x = new int[chars.length]; // 列坐标
// 求每个字符的位置 x,y
for(int c = 0; c < chars.length; c++) {
y[c] = 0; // 当做~`键处理
x[c] = -1;
// 先在c1中查找
for (int i = 0; i < keyboard1.size(); i++) {
for (int j = 0; j < keyboard1.get(i).size(); j++) {
if (chars[c] == keyboard1.get(i).get(j)) {
y[c] = i;
x[c] = j;
}
}
}
if (x[c] != -1) continue;
// 如果在c1中没找到,在c2中查找
for (int i = 0; i < keyboard2.size(); i++) {
for (int j = 0; j < keyboard2.get(i).size(); j++) {
if (chars[c] == keyboard2.get(i).get(j)) {
y[c] = i;
x[c] = j;
}
}
}
}
// System.out.println("x:"+Arrays.toString(x));
// System.out.println("y:"+Arrays.toString(y));
// 判断是否键盘连续
for (int c = 1; c < chars.length-1; c++) {
// 检查水平方向(同一行连续)
if (y[c - 1] == y[c] && y[c] == y[c + 1]) {
if ((x[c - 1] + 1 == x[c] && x[c] + 1 == x[c + 1]) ||
(x[c + 1] + 1 == x[c] && x[c] + 1 == x[c - 1])) {
return true;
}
}
// 检查垂直方向(同一列连续)
else if (x[c - 1] == x[c] && x[c] == x[c + 1]) {
if ((y[c - 1] + 1 == y[c] && y[c] + 1 == y[c + 1]) ||
(y[c + 1] + 1 == y[c] && y[c] + 1 == y[c - 1])) {
return true;
}
}
// 检查斜向 如 8uhb bhu8(右上到左下 或者 左下到右上)
else if (
x[c-1] - 1 == x[c] && x[c] - 1 == x[c+1] && y[c-1] + 1 == y[c] && y[c] + 1 == y[c+1] ||
x[c-1] + 1 == x[c] && x[c] + 1 == x[c+1] && y[c-1] - 1 == y[c] && y[c] - 1 == y[c+1]
) {
return true;
}
}
return false;
}
public static void main(String[] args) {
PwdValidator.validatePassword("16charslongpass~", "user");
}
}