有没有一种方法可以简化正则表达式匹配字符?

时间:2020-02-25 10:07:29

标签: javascript regex

我正在尝试构建ECMAScript(JavaScript)风味正则表达式,以根据以下条件测试密码的强度:

    Characters Used          Password Strength Length
   ABC  abc  123  #$&      WEAK  ...
1   x                      1-5   ...   
2        x                 1-5
3             x            1-7
4                  x       1-5
5   x    x                 1-4   
6   x         x            1-4
7   x              x       1-4
8        x    x            1-4 
9        x         x       1-4       
10            x    x       1-4     
11  x    x    x            1-4           
12  x    x         x       1-3   
13  x        x     x       1-4           
14      x    x     x       1-4  
15  x   x    x     x       1-3     

因此,2ABCD0123456abCdaA#等密码应标记为弱密码。指定组合012345678aA1#等较长的密码不应该。

这是我很长的regex atm(基本上根据上表通过组粘合在一起):

/^(([A-Za-z&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,3})|([a-z0-9&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,4})|([A-Z0-9&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,4})|([a-zA-Z0-9]{1,4})|([a-z]{1,5})|([A-Z]{1,5})|([0-9]{1,7})|([&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,5}))$/

匹配行(在表上方):12

/([A-Za-z&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,3})/

匹配行:14、9

/([a-z0-9&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,4})/

匹配行:13、10、7

/([A-Z0-9&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,4})/

匹配行:11、8、6、5

/([a-zA-Z0-9]{1,4})/

匹配行:2

/([a-z]{1,5})/

匹配行:1

/([A-Z]{1,5})/

匹配行:3

/([0-9]{1,7})/

匹配行:4

/([&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,5})/

是否可以重用我在[] [&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]中指定的特殊字符,因此不必在每个组中都写所有特殊字符?

2 个答案:

答案 0 :(得分:2)

有没有一种方法可以重用我在[] ...中指定的特殊字符,因此我不必在每个组中都写所有特殊字符?

不带正则表达式文字,不。

不过,您可以使用RegExp构造函数来实现。您可以使用String.raw来减轻它想要一个字符串的事实,因此您不必担心转义反斜杠:

const chars = String.raw`[the chars]`;
const rex = new RegExp(String.raw`^...${chars}...${chars}...$`);

您可以通过为此创建一个特定的标记函数来进一步实现此功能(这是我新书第10章的示例;有关详细信息,请参见我的个人资料):

const createRegex = (template, ...values) => {
    // Build the source from the raw text segments and values
    const source = String.raw(template, ...values);
    // Check it's in /expr/flags form
    const match = /^\/(.+)\/([a-z]*)$/.exec(source);
    if (!match) {
        throw new Error("Invalid regular expression");
    }
    // Get the expression and flags, create
    const [, expr, flags = ""] = match;
    return new RegExp(expr, flags);
};

然后:

const chars = String.raw`[the chars]`;
const rex = createRegex`/^...${chars}...${chars}...$/`;

答案 1 :(得分:0)

我不确定您使用的是哪个正则表达式引擎。但是,如果是Perl或Ruby,则可以使用子例程在很大程度上实现这一目标。子例程是正则表达式中的重复模式。

您可能知道反向引用。但是,子例程与反向引用不同。在反向引用的情况下,捕获组的内容是匹配的,而不是模式。但是,对于子例程,将重复模式匹配。

让我们举个例子。

  • 测试字符串:abcd-defg
  • Ruby 中的正则表达式:/(?<dd>[a-z]+)-\g<dd>/。比赛将会成功。
  • \g<dd>部分是Ruby中名为dd的组的子例程调用。 (\g<group_name>是Ruby regex样式。对于您使用的引擎,它可能有所不同。)

更多详细信息在这里:


就您而言,我认为您可以为每个组在正则表达式中首次出现时命名,然后将其称为子例程。例如,让我们打电话

  • [A-Z]A
  • [a-z]a
  • [0-9]n
  • 特殊字符集设置为s(不确定我是否正确使用此模式。)

然后,用于12的模式 /([A-Za-z&*@\^}\]\\):,$=!><–{[(%+#;\/~_?.]{1,3})/变为

/((\g<A>|\g<a>|\g<s>)){1,3})/

A OR a OR s repeated 1-3 times

并且 11、8、6、5 的模式变为/([a-zA-Z0-9]{1,4})/

/((\g<a>|\g<A>|\g<n>)){1,4})/

a OR A OR n repeated 1-4 times