【问题标题】:Regex working in JavaScript but not PHP正则表达式在 JavaScript 但不是 PHP
【发布时间】:2017-09-15 17:09:07
【问题描述】:

我的网站有一个注册页面。

当用户填写表单时,他们会通过 JavaScript 正则表达式获得实时验证,效果很好。这是通过以下方式完成的:

var password = document.getElementsByName("password")[0].value;
var pattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)([a-zA-Z0-9!\"\#$%&\'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]{6,})$/;
if(pattern.test(password)){
    document.getElementById("check_password").innerHTML = "Password is valid.";
} else {
    document.getElementById("check_password").innerHTML = "Password is invalid. It should have at least 6 characters, and 1 lowercase letter, uppercase letter, and number.";
}

当用户通过以下方式提交表单时使用 PHP 正则表达式:

if(!preg_match("/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)([a-zA-Z0-9!\"\#$%&\'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]{6,})$/", $_POST["password"])){
        $error = "Password is invalid. It should have at least 6 characters, and 1 lowercase letter, uppercase letter, and number.";
}

但是,即使 JavaScript 没有,PHP 也会不断抛出错误。两个正则表达式是相同的,并且已经在 PHP 设置和 JavaScript 设置中进行了测试。但它在 JavaScript 中有效,但在 PHP 中无效!

为什么它在 PHP 中不起作用,我该如何解决这个问题?

【问题讨论】:

  • 分享有问题的输入。
  • heHE12 就是一个例子。它将匹配 regex101.com 上看到的正则表达式,但在 PHP 的 preg_match() 中仍然不匹配
  • @revo 这个密码不应该是个好密码
  • @revo 这不是复制品吗?代码说它应该通过时失败!并删除 !真的没有意义。
  • 问题出在反斜杠上,各位。

标签: javascript php regex


【解决方案1】:

问题来自反斜杠。要在 php 正则表达式字符串中计算文字反斜杠,您需要使用 4 个反斜杠(您需要为字符串转义一次,为正则表达式转义一次,因为它也是一个正则表达式特殊字符):

if(!preg_match("/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)([a-zA-Z0-9!\"\#$%&\'()*+,\-.\/:;<=>?@\[\\\\\]^_`{|}~]{6,})$/", $_POST["password"])){
    $error = "Password is invalid. It should have at least 6 characters, and 1 lowercase letter, uppercase letter, and number.";
}

请注意,如果您决定使用 Javascript 字符串中的 RegExp 构造函数来定义模式,也是一样的:

var re = new RegExp("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)([-a-zA-Z0-9!\"#$%&'()*+,./:;<=>?@\\[\\]\\\\^_`{|}~]{6,})$");

顺便说一句,为了避免这个问题,字符类[a-zA-Z0-9!\"\#$%&amp;\'()*+,\-.\/:;&lt;=&gt;?@\[\\\\\]^_``{|}~] 可以缩短为[!-~]。此外,您不需要捕获组:

if(!preg_match("/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[!-~]{6,}$/", $_POST["password"])){
    $error = "Password is invalid. It should have at least 6 characters, and 1 lowercase letter, uppercase letter, and number.";
}

最后,JavaScript 和 PHP 之间的锚点 $ 存在细微差别。在这两种语言中,它匹配字符串的结尾(默认情况下没有多行模式),但在 PHP 中,它也匹配行尾,当该行后跟换行符 \n 就在字符串的结尾之前.换句话说,字符串"Password0\n" 也匹配您的模式,因为$ 锚点匹配0\n(在\n 的位置)。

为了避免这个问题,有两种可能:

  • 您可以使用D modifier (PCRE_DOLLAR_ENDONLY):
    /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[!-~]{6,}$/D
  • 或将$ 更改为\z(无论模式如何,始终匹配且仅匹配字符串的结尾):
    /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[!-~]{6,}\z/

【讨论】:

  • 是的!这是对的。实际上它应该是 2 个反斜杠,因为 4 将毫无意义,因为我试图包括整个集合,而 4 将是一种浪费。非常感谢!
  • 你能解释一下为什么它可以缩短为 [!-~]
  • @ngmh:这是一个包含所有字符的简单字符范围,请参见 ascii 表。
【解决方案2】:

你应该检查 preg_match 是否返回:

如果未找到,则返回 INT(0)。 如果找到则返回 INT(1)。 如果发生错误,则返回 BOOL(false)。

【讨论】:

  • 我必须使用 preg_mach() == 0?
  • 没错,您正在检查它是否返回 false,这意味着它是否发生了错误。
  • 这个答案隐含地促进了一个正确的解决方案。投票。
  • 这实际上不是问题。
  • 那么这只是问题的一部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 2010-09-07
  • 1970-01-01
相关资源
最近更新 更多