【问题标题】:Regex to match standard and outlier input正则表达式匹配标准和异常值输入
【发布时间】:2015-01-14 20:09:48
【问题描述】:

一段时间以来,我一直在使用 jQuery validation 的正则表达式,以确保我的用户输入有效的绘图名称字符串。在过去的一周里,我们增加了使用字符串有些不同的第 3 方设备的功能。我的任务是允许这些字符串以及之前的集合作为有效输入。我将它们发送给改编自 this SO answer 的验证器:

$.validator.addMethod("accept", function (value, element, param)
{
    return value.match(new RegExp("^" + param + "$"));
});

请注意,我正在添加 ^$ 字符。

像这样:

        drawingName: {
            required: true,
            accept: "[0-9]{4,5}[\\.?\\w*]{0,4}"
        },

双反斜杠转义单反斜杠以在验证器中使用。如果您正在测试 http://www.rubular.com/ 之类的内容,则需要使用单反斜杠。

上一组(我对其进行了通用表示,其中“X”代表字母,“0”代表数字,小数点就是它们的含义)由以下有效可能性组成:

00000
00000.0
00000.00
00000.X
000000
000000X
00000X
00000X.0
00000X.0X
00000X0.0
00000XX.0
0000X.0

我的数据中有成千上万个这样的变体,不可能改变它们。该公司正在制定标准化命名法,但我们出售给客户的设备几十年来都可以返回维修、维护和校准:因此我们永远无法摆脱旧系统。

新的字符串变体如下所示:

XXX-0000
XXX-00000
XXX-000000

我已修改原始正则表达式以适应更改:[\\w{3}-]*\\d{4,5}[\\.?\\w*]{0,4}

我也尝试过\p{L}{3}?-?\d{4,6}\.?\w{0,2}\.?\w{0,2},但也出现了同样的问题(见下文)。

两者都有效,但在我的测试中,我注意到它们将允许在有效可能性的末尾添加看似无限数量的额外字符。 (我很确定旧的正则表达式允许相同类型的错误输入。)

因此,要捕获新字符串,我需要查找三个字母,后跟一个破折号,然后是四到六个数字(类似于:[\w{3}-]?\d{4,6}?[/p{L}{3}-]?\d{4,6}?)...容纳以前的图纸名称,四到五位可能后跟一个字母,数字或一个小数点,可能后跟一个字母或数字,可能后跟一个数字或字母(令人困惑,是吗?) - 类似于这个:\d{4,5}[\.\w*]{0,4} 我认为这部分的问题在于w 后面的星号,但我不确定如何修复它或正确地将正则表达式的两个不同部分连接在一起。

我正在寻找的是一个单一的正则表达式,它允许我使用上述所有字符串变体筛选有效输入,但阻止无效输入。我知道我可以简单地添加另一个验证规则,这可能是我必须做的,但我想看看是否可以在单个正则表达式中完成。

编辑:

这是我在代码中使用的 Lucas 建议的最终解决方案,经过一些修改以不使用 \w,如下面他的回答中指出的那样:

(?:\\d{4,5}[0-9a-zA-Z]{0,2}(?:\\.[0-9a-zA-Z]{1,2})?|[a-zA-Z]{3}-\\d{6})

【问题讨论】:

    标签: javascript jquery regex validation


    【解决方案1】:

    你可以这样做:

    ^(?:\d{4,5}\w{0,2}(?:\.\w{1,2})?|\w{3}-\d{6})$
    

    Demo

    我只是使用了 alternative operator (|) 来区分新旧格式。

    请注意,您的原始正则表达式 ([0-9]{4,5}[\.?\w*]{0,4})可能 存在问题:[\.?\w*] 表示 .?单词字符 或 @987654328 @,这似乎不是你所追求的。我根据您的示例对其进行了更严格的处理,但您可能需要对其进行调整。

    另外,请注意 \w 在 JS 中的意思是 [0-9a-zA-Z_] - 这可能不是您所追求的(尤其是下划线)。

    【讨论】:

    • 谢谢!我没有考虑能够将正则表达式分成两个独立的部分。你也对,\w 并不是我真正想要的,所以我想我会用[0-9a-zA-Z] 代替它。还要感谢演示,我不知道该站点存在。我会让你知道我的工作。
    【解决方案2】:

    单个正则表达式

    这是一个简单的(相对于您的问题的规模)单个正则表达式,它解释了所提供的所有示例输入——但 not “允许附加看似无限数量的额外字符有效可能性的终结”:

    ^(\d{4}(\d([\dA-Z]|(\.(\d{1,2}|[A-Z]))|\d[A-Z]|[A-Z](\.\d[A-Z]?|[\dA-Z]\.\d))?|[A-Z]\.\d)|[A-Z]{3}-\d{4,6})$
    

    Debuggex Demo

    以下是使用提供的示例输入测试正则表达式的 sn-p:

    var regex = new RegExp("^(\\d{4}(\\d([\\dA-Z]|(\\.(\\d{1,2}|[A-Z]))|\\d[A-Z]|[A-Z](\\.\\d[A-Z]?|[\\dA-Z]\\.\\d))?|[A-Z]\\.\\d)|[A-Z]{3}-\\d{4,6})$");
    // tests for the sample inputs provided that are all expected to match
    var tests = [
        '12345',
        '12345.6',
        '12345.67',
        '12345.A',
        '123456',
        '123456A',
        '12345A',
        '12345A.6',
        '12345A.6B',
        '12345A6.7',
        '12345AB.6',
        '1234A.5',
        'ABC-1234',
        'ABC-12345',
        'ABC-123456'
    ];
    
    for (var i = 0; i < tests.length; i++) {
        var result = "'" + tests[i] + "' => ";
                    
        if (regex.test(tests[i])) {
            result += 'Yup!';
        } else {
            result += 'Nope...';
        }
    
        console.log(result);
    }

    基本原理

    很明显,顶层交替(|)是旧变体/新变体拆分的关键;但我认为以\d{4,5}(特别是{4,5} 量词)开头的旧变体是过度匹配问题的根源。

    取而代之的是所有旧变体的共同点 - 四个开头数字(即\d{4}):这使您可以直接使用后续的内部交替来匹配旧变体' 分歧超出了他们的前四个字符。

    详情

    效果如下:

    • ^ – 输入字符串的开始
    • ( – 旧变体和新变体的第一级交替开始
    • \d{4} – 所有旧变体都以四个数字开头
      • ( – 旧变体主要分歧的第二级交替开始
      • \d – 第五位数字
        • ( – 前五个字符是数字的可选分歧的第 3 级交替开始
        • [\dA-Z] – 数字或字母
        • |(第三级)
        • (\.(\d{1,2}|[A-Z])) – 一个句点和1)一个或两个数字OR 2)一个字母
        • |OR(第三级)
        • \d[A-Z] – 一个数字和一个字母
        • |OR(第三级)
        • [A-Z](\.\d[A-Z]?|[\dA-Z]\.\d) – 一个字母和 1) 句点、数字和可选的字母 OR 2)数字或字母、句点和数字
        • )? – 前五个字符是数字的可选分歧的第三级交替结束
      • |OR(第二级)
      • [A-Z]\.\d – 一个字母、一个句点和一个数字
      • ) – 旧变体主要分歧的第二级交替结束
    • | - (一级)
    • [A-Z]{3}-\d{4,6} – 新变种
    • ) – 旧变体和新变体的第一级交替结束
    • $ - 输入字符串结束

    上面的 Debuggex 图形以图表方式解释了所有这些,但(其中一些)可能更容易理解。

    可维护性

    使用一个正则表达式来处理如此多的变体自然会使可维护性成为一项挑战。

    为了支持可维护性:

    1. 将我在上面的详细信息细分中显示的子模式分配给不同的字符串变量。
    2. 然后通过连接子模式的字符串来构建单个模式。

    这样做的好处是允许您注释每个子模式的字符串变量(就像我在 详细信息 细分中注释了每个项目符号一样)。

    【讨论】:

    • 感谢您的帮助,目前我将尝试使用 Lucas 的解决方案,因为它似乎更容易维护,但我也会尝试剖析您的解决方案,所以我了解发生了什么。也感谢提供演示站点,我之前使用过一两次,但那是很久以前的事了,我已经忘记了。
    • 只需阅读您编辑的答案,感谢您指出问题,我将尝试将其应用于上述解决方案。感谢您花时间向我解释。
    • 哇,太棒了扩展了原始答案。感谢您付出额外的努力并花时间这样做,我真的很感激。
    猜你喜欢
    • 2011-08-05
    • 2023-03-25
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    相关资源
    最近更新 更多