2

给定一个字符串,它必须具有以下内容:

  1. 只有一个数字
  2. (@#$*) 中只有一个特殊字符
  3. 6个小写字母

字符串可以是上述条件的任意组合,并且长度必须为 8。

例子:

  1. 2@qwerty
  2. 1asddfg

  3. qwe*yt2u
  4. qw2wqia

到目前为止,这是我的正则表达式:

!/^(?=.*[0-9])(?=.*[^a-z])(?=.*[a-z])(?=.*[@#$*])\S{8,}$/.test(string)

它适用于上述情况,但在以下情况下会中断:

  1. 2@2qwert
  2. 2@@qwert

我错过了什么?

4

5 回答 5

3

我错过了什么?

您的测试“2@2qwert”和“2@@qwert”与您的正则表达式不正确匹配的原因是因为其中没有任何内容需要至少 6 个小写字母。根据对此问题的其他答案和评论,我会说将您的(?=.*[a-z])条款替换为(?=(.*?[a-z]){6}).

可以进行的其他一些小的改进:

  • 您可以删除多余的(?=.*[^a-z])子句,因为所有这些都是说字符串应该包含至少 1 个非字母,这已经由数字和特殊字符要求确定。
  • 将 [0-9] 替换为 \d。
  • 在字符匹配 (.*) 之前匹配通配符的 3 个位置中,如果将这些设置为非贪婪的,那么 RegExp 引擎的速度会稍快一些,以便在搜索字符串以进行匹配时减少回溯。这是通过放置一个?之后 * (。*?)。

根据您的正则表达式将其放在一起:

/^(?=.*?\d)(?=(.*?[a-z]){6})(?=.*?[@#$*])\S{8,}$/

这成功匹配您的前 4 个字符串,但不是最后 2 个。

(如果您想要一个可读的验证功能,我的原始回复如下。)

function validate(str)
{
  // test for digit
  if( !/\d/.test(str) ) return false;
  // test for special character
  if( !/[@#$*]/.test(str) ) return false;
  // test for 6 lowercase letters
  var letters = str.match(/[a-z]/g);
  return letters != null && letters.length == 6;
}

var tests = [ '2@qwerty', '#1asddfg', 'qwe*yt2u', '#qw2wqia', '2@2qwert', '2@@qwert' ];
for( var i=0 ; i<tests.length ; ++i )
  document.writeln(tests[i] + ": " + validate(tests[i]) + "<br/>\n");
于 2013-08-27T21:07:19.347 回答
3

您的中断案例应该中断,因为它们不满足条件#3。话虽如此,我认为结合使用 JavaScript 和 Regex 可能更容易:

function isValid(input) {
  return (input && input.length === 8)             /* make sure its 8 characters */
         && /[0-9]/.test(input)                    /* make sure it contains at least one digit */
         && /[@#$*]/.test(input)                   /* make sure it contains at least one special character */
         && /([^a-z]*[a-z]){6}.*/.test(input);     /* make sure it contains at least 6 lower case chars */ 
}

console.log(isValid('2@qwerty'));    // true
console.log(isValid('#1asddfg'));    // true
console.log(isValid('qwe*yt2u'));    // true
console.log(isValid('#qw2wqia'));    // true
console.log(isValid('2@2qwert'));    // false
console.log(isValid('2@@qwert'));    // false
console.log(isValid('2@qwerty'));   // now true as it satisfies #3

编辑:根据@Sniffer 的输入更新了至少 6 个字符的检查(学习新东西很有趣,请参阅评论!)

于 2013-08-27T21:22:15.307 回答
2

好吧,我想出了一个正则表达式,它可能会做你想做的事,但你可能不喜欢它的外观,但它背后的原理很简单:

^(?=^.{8}$)(?=\D*[0-9])(?=[^@#$*]*[@#$*])(?=([^a-z]*[a-z]){6})\S{8}$

此表达式首先确保只有 8 个字符(?=^.{8}$)

现在表达式检查是否不再有一个数字(?=\D*[0-9]),然后它确保有一个特殊符号(?=[^@#$*]*[@#$*])

现在表达式保证有 6 个小写字符(?=([^a-z]*[a-z]){6})

所以我们保证有一个数字,一个特殊符号和6个小写字符,总和是8个字符,所以字符串应该是有效的。

这当然不是最好的方法,因为您可能应该将此操作分成多个步骤,但我想尝试用一个表达式来做这件事以获得乐趣,如果您发现任何问题,请告诉我。

于 2013-08-27T21:24:29.530 回答
2

描述

您的表达中断是因为:

^(?=.*[0-9])(?=.*[^a-z])(?=.*[a-z])(?=.*[@#$*])\S{8,}$
            ^^^^^^^^^^^^                       ^^^^^^
  • [^a-z]是一个否定字符类,所以这将匹配任何不是a-z. 我不确定这部分表达式的目的是什么。
  • \S将匹配任何非空白字符。这允许字母、数字、unicode 字符、换行符、任何符号...等。
  • {8,}将允许 8 个或更多前面的字符。这允许字符串是无限长的。在您的帖子中,您希望字符串最多包含 8 个字符。
  • 同样作为最佳实践,您应该始终转义,#因为这可以用作某些版本的正则表达式中的注释字符,因此表达式已准备好以防x使用该选项。

我会像这样修改你的表达式:

  • 要求字符串有 1 个数字
  • 要求字符串有 1 个@#$*符号
  • 要求字符串有 6a-z个小写字母(确保不要使用不区分大小写的选项)
  • 要求字符串的总长度为 8 个字符

^(?=.*?[0-9])(?=.*?[@\#$*])(?=(?:.*?[a-z]){6}).{8}$

现场演示

在此处输入图像描述

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    .*?                      any character except \n (0 or more times
                             (matching the least amount possible))
--------------------------------------------------------------------------------
    [0-9]                    any character of: '0' to '9'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    .*?                      any character except \n (0 or more times
                             (matching the least amount possible))
--------------------------------------------------------------------------------
    [@\#$*]                  any character of: '@', '\#', '$', '*'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    (?:                      group, but do not capture (6 times):
--------------------------------------------------------------------------------
      .*?                      any character except \n (0 or more
                               times (matching the least amount
                               possible))
--------------------------------------------------------------------------------
      [a-z]                    any character of: 'a' to 'z'
--------------------------------------------------------------------------------
    ){6}                     end of grouping
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  .{8}                     any character except \n (8 times)
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string
于 2013-08-28T03:28:59.340 回答
2

这个正则表达式可以满足您的需要:

^(?=\D*\d\D*$)(?=[^@#$*]*[@#$*][^@#$*]*$)[@#$*\da-z]{8}$

它使用 2 个前瞻(锚定开始)来准确断言 1 个数字和 1 个特殊字符,以及一个用于所有有效字符(乘以 8)的简单字符类,因此其余的必须是小写的(无需精确计数 6)。

在 rubular 上查看您的测试用例的现场演示。

于 2013-08-28T13:57:42.923 回答