共被编辑 8 次

版本 更新时间 贡献者 编辑原因 操作
#r8 2016年09月28日 wdy1184433 更新问题 查看

密码规则正则匹配,另外问题:为什么正则表达式效率低?

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba、aaa、111、AAA)

echo !preg_match('/\d{3,}|[a-zA-Z]{3,}/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。

再问个问题:为什么正则表达式效率低?

因为连续的数字,字母用正则表达式判断太复杂而且效率低,所以采用逻辑代码判断的方式,以下是我用PHP写的代码,php5.5.12 初步测试成功。

<?php
define('PWD_MAX_LENGTH', 16);
define('PWD_MIN_LENGTH', 6);

/**
 * @time 2016年8月29日11:52:29
 */
class User_Common {

    /**
     * 密码格式:6-16位数字字母组合
     * 不包含特殊字符。
     * 必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
     * 连续3位及以上数字不能连续(例如123、876)
     * 连续3位及以上的字母不能连续(例如abc、cba)
     * @param $password
     * @return bool
     * @throws \Exception
     */
    public static function checkPassword($password) {
        self::pwdLengthCheck($password);
        self::pwdCharValid($password);
    }

    /**
     * @param $password
     * @return bool
     * @throws \Exception
     */
    private static function pwdCharValid($password) {
        if (!ctype_alnum($password)) {
            throw new Exception('不包含特殊字符', 10002);
        }
        $includeNumber = false;
        $includeUpperLetter = false;
        $includeLowerLetter = false;
        $length = strlen($password);

        for ($i=0; $i < $length; $i++) {
            $char = $password[$i];
            $includeUpperLetter = (!$includeUpperLetter && ctype_upper($char)) ? true : $includeUpperLetter;
            $includeNumber = (!$includeNumber && ctype_digit($char)) ? true : $includeNumber;
            $includeLowerLetter = (!$includeLowerLetter && ctype_lower($char)) ? true : $includeLowerLetter;
            if ($i != 0 && !empty($password[$i+1])
                && abs(ord($password[$i]) - ord($password[$i-1])) <=1
                && ord($password[$i]) - ord($password[$i-1]) == ord($password[$i+1]) - ord($password[$i])) {
                throw new Exception('连续3位及以上数字或字母不能连续(例如123、876)', 10004);
            }
        }
        if ($includeLowerLetter && $includeNumber && $includeUpperLetter) {
            return 2;
        } else {
            throw new Exception('必须同时包含数字、大写字母,小写字母3种字符,区分大小写', 10003);
        }
    }

    private static function pwdLengthCheck($password) {
        if (strlen($password) > PWD_MAX_LENGTH || strlen($password) < PWD_MIN_LENGTH) {
            throw new Exception('密码格式:6-16位数字字母组合', 10001);
        }
    }

    /**
     * 检查是否为1开头的11位数字手机号
     * @param int $phoneNumber
     * @return boolean 是否匹配
     */
    public static function checkPhoneNumber($phoneNumber) {
        return preg_match('/^1\d{10}$/', $phoneNumber);
    }
}



try {
    var_dump(User_Common::checkPassword('AbA001'));
} catch (Exception $e) {
    echo $e->getMessage();
}

#r7 2016年09月28日 wdy1184433 代码整理 查看

密码规则正则匹配,另外问题:为什么正则表达式效率低?

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba、aaa、111、AAA)

echo !preg_match('/\d{3,}|[a-zA-Z]{3,}/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。

再问个问题:为什么正则表达式效率低?

因为连续的数字,字母用正则表达式判断太复杂而且效率低,所以采用逻辑代码判断的方式,以下是我用PHP写的代码,php5.5.12 初步测试成功。

<?php
define('PWD_MAX_LENGTH', 16);
define('PWD_MIN_LENGTH', 6);

/**
 * @time 2016年8月29日11:52:29
 */
class User_Common {

    /**
     * 密码格式:6-16位数字字母组合
     * 不包含特殊字符。
     * 必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
     * 连续3位及以上数字不能连续(例如123、876)
     * 连续3位及以上的字母不能连续(例如abc、cba)
     * @param $password
     * @return bool
     * @throws \Exception
     */
    public static function checkPassword($password) {
        self::pwdLengthCheck($password);
        self::pwdCharValid($password);
    }

    /**
     * @param $password
     * @return bool
     * @throws \Exception
     */
    private static function pwdCharValid($password) {
        if (!ctype_alnum($password)) {
            throw new Exception('不包含特殊字符', 10002);
        }
        $includeNumber = false;
        $includeUpperLetter = false;
        $includeLowerLetter = false;
        $length = strlen($password);

        for ($i=0; $i < $length; $i++) {
            $char = $password[$i];
            // echo ctype_upper($char) ? 'upper'.$char : 0;
            // echo $char;
            // var_dump(ctype_digit($char));
            // echo ctype_digit($char) ? 'digit' : 0;
            // echo ctype_lower($char) ? 'lower'.$char : 0;
            $includeUpperLetter = (!$includeUpperLetter && ctype_upper($char)) ? true : $includeUpperLetter;
            $includeNumber = (!$includeNumber && ctype_digit($char)) ? true : $includeNumber;
            $includeLowerLetter = (!$includeLowerLetter && ctype_lower($char)) ? true : $includeLowerLetter;
            if ($i != 0 && !empty($password[$i+1])
                && abs(ord($password[$i]) - ord($password[$i-1])) <=1
                && ord($password[$i]) - ord($password[$i-1]) == ord($password[$i+1]) - ord($password[$i])) {
                throw new Exception('连续3位及以上数字或字母不能连续(例如123、876)', 10004);
            }
        }
        if ($includeLowerLetter && $includeNumber && $includeUpperLetter) {
            return 2;
        } else {
            throw new Exception('必须同时包含数字、大写字母,小写字母3种字符,区分大小写', 10003);
        }
    }

    private static function pwdLengthCheck($password) {
        if (strlen($password) > PWD_MAX_LENGTH || strlen($password) < PWD_MIN_LENGTH) {
            throw new Exception('密码格式:6-16位数字字母组合', 10001);
        }
    }

    /**
     * 检查是否为1开头的11位数字手机号
     * @param int $phoneNumber
     * @return boolean 是否匹配
     */
    public static function checkPhoneNumber($phoneNumber) {
        return preg_match('/^1\d{10}$/', $phoneNumber);
    }
}



try {
    var_dump(User_Common::checkPassword('AbA001'));
} catch (Exception $e) {
    echo $e->getMessage();
}

#r6 2016年09月15日 wdy1184433 修正错别字及语法 查看

密码规则正则匹配,另外问题:为什么正则表达式效率低?

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba、aaa、111、AAA)

echo !preg_match('/\d{3,}|[a-zA-Z]{3,}/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。

再问个问题:为什么正则表达式效率低?

因为连续的数字,字母用正则表达式判断太复杂而且效率低,所以采用逻辑代码判断的方式,以下是我用PHP写的代码,php5.5.12 初步测试成功。

/**
 * 密码格式:6-16位数字字母组合
 * 不包含特殊字符。
 * 必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
 * 连续3位及以上数字不能连续(例如123、876)
 * 连续3位及以上的字母不能连续(例如abc、cba)
 * @param string $password
 * @return boolean 是否匹配
 */
function CheckPassword($password){
    if (strlen($password) > 16 || strlen($password) < 6) {
        return false;
    }

    // ASCII code vallue
    $upperLetter = range(65, 90);
    $lowerLetter = range(97, 122);
    $number = range(48, 57);

    $includeNumber = false;
    $includeUpperLetter = false;
    $includeLowerLetter = false;
    $continuousCharNum = 0;

    for ($i=0; !empty($password[$i]); $i++) {
        // 特殊字符
        if (!in_array(ord($password[$i]), array_merge($upperLetter, $lowerLetter, $number))) {
            return false;
        }
        // 大写字母
        if (!$includeUpperLetter && in_array(ord($password[$i]), $upperLetter)) {
            $includeUpperLetter = true;
        }
        // 数字
        if (!$includeNumber && in_array(ord($password[$i]), $number)) {
            $includeNumber = true;
        }
        // 小写字母
        if (!$includeLowerLetter && in_array(ord($password[$i]), $lowerLetter)) {
            $includeLowerLetter = true;
        }
        if ($i != 0 && !empty($password[$i+1])
            && abs(ord($password[$i]) - ord($password[$i-1])) <= 1 && ord($password[$i]) - ord($password[$i-1]) == ord($password[$i+1]) - ord($password[$i])) {
            return false;
        }
    }
    if ($includeLowerLetter && $includeNumber && $includeUpperLetter) {
        return true;
    } else {
        return false;
    }
}
#r5 2016年08月22日 wdy1184433 更新问题 查看

密码规则正则匹配,另外问题:为什么正则表达式效率低?

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba、aaa、111、AAA)

echo !preg_match('/\d{3,}|[a-zA-Z]{3,}/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。

再问个问题:为什么正则表达式效率低?

因为连续的数字,字母用正则表达式判断太复杂而且效率低,所以采用逻辑代码判断的方式,一下是我用PHP写的代码,php5.5.12 初步测试成功。

/**
 * 密码格式:6-16位数字字母组合
 * 不包含特殊字符。
 * 必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
 * 连续3位及以上数字不能连续(例如123、876)
 * 连续3位及以上的字母不能连续(例如abc、cba)
 * @param string $password
 * @return boolean 是否匹配
 */
function CheckPassword($password){
    if (strlen($password) > 16 || strlen($password) < 6) {
        return false;
    }

    // ASCII code vallue
    $upperLetter = range(65, 90);
    $lowerLetter = range(97, 122);
    $number = range(48, 57);

    $includeNumber = false;
    $includeUpperLetter = false;
    $includeLowerLetter = false;
    $continuousCharNum = 0;

    for ($i=0; !empty($password[$i]); $i++) {
        // 特殊字符
        if (!in_array(ord($password[$i]), array_merge($upperLetter, $lowerLetter, $number))) {
            return false;
        }
        // 大写字母
        if (!$includeUpperLetter && in_array(ord($password[$i]), $upperLetter)) {
            $includeUpperLetter = true;
        }
        // 数字
        if (!$includeNumber && in_array(ord($password[$i]), $number)) {
            $includeNumber = true;
        }
        // 小写字母
        if (!$includeLowerLetter && in_array(ord($password[$i]), $lowerLetter)) {
            $includeLowerLetter = true;
        }
        if ($i != 0 && !empty($password[$i+1])
            && abs(ord($password[$i]) - ord($password[$i-1])) <= 1 && ord($password[$i]) - ord($password[$i-1]) == ord($password[$i+1]) - ord($password[$i])) {
            return false;
        }
    }
    if ($includeLowerLetter && $includeNumber && $includeUpperLetter) {
        return true;
    } else {
        return false;
    }
}
#r4 2016年08月18日 wdy1184433 补充内容 | 添加代码 | 修改标题 查看

密码规则正则匹配,另外问题:为什么正则表达式效率低?

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba)

echo !preg_match('/\d{3,}|[a-zA-Z]{3,}/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。

又改进了一下:

return preg_match('/^([a-zA-Z0-9]){6,16}$/', $password) &&
preg_match('/[a-z]+/', $password) &&
preg_match('/\d+/', $password) &&
preg_match('/[A-Z]+/', $password) &&
!preg_match('/\d{3,}|[a-zA-Z]{3,}/', $password);

再问个问题:为什么正则表达式效率低?

#r3 2016年08月18日 wdy1184433 修改代码 查看

密码规则设置

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba)

echo !preg_match('/\d{3,}|[a-zA-Z]{3,}/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。

#r2 2016年08月18日 wdy1184433 更新问题 查看

密码规则设置

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba)

echo !preg_match('/(\d{3,}|[a-zA-Z]{3,})+/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。

#r1 2016年08月18日 wdy1184433 创建问题 查看

密码规则设置

规则如下:
密码格式:6-16位数字字母组合
不包含特殊字符。
必须同时包含数字、大写字母,小写字母3种字符,区分大小写。
连续3位及以上数字不能连续(例如123、876)
连续3位及以上的字母不能连续(例如abc、cba)

echo !preg_match('/[\d{3,}|[a-zA-Z]{3,}]+/', $password);
echo preg_match('/\d+/', $password);
echo preg_match('/[a-z]+/', $password);
echo preg_match('/[A-Z]+/', $password);
echo preg_match('/^([a-zA-Z0-9]){6,16}$/', $password);

以上是需求和我想出来的解决方法

但是总想能用更简洁的方式来匹配出来,希望有人能有更好的思路。