3

我正在尝试以最有效的方式验证 2 种不同的方式来识别位置字符串,但是任何一种都可能有轻微的变化,或者在主字符串之前和之后都可以有一组字符。

有效值:

1号

14-36-085-17 W6
14-36-085-17-W6
14-36-085-17W6

2号

D 096 H 094A15

数字 3 上述任何一个都可以在主字符串之前有 3 位数字,在主字符串之后可以有 2 位数字(或没有)

100 14-36-085-17W6 00
200 D 096 H 094A15 00

在这 5 个附加字符中,这些是规则:

  • 第一 - 总是 1 或 2
  • 第二 - 总是 0
  • 第三 - 0 到 9
  • 第 4 - 总是 0
  • 第 5 - 0 到 9

所以,我认为应该是[1-2]0[0-9]0[0-9]分别是。另请注意,前 3 位数字取决于后 2 位数字,反之亦然。前 3 位只有在有后 2 位时才有,后 2 位只有在前 3 位有时才有。

这给了我们以下不应该匹配的无效字符串:

100 14-36-085-17W6
14-36-085-17W6 00

这是我的两个主要数字的代码

function func(s) 
{
  var re = /(^\d{2}-\d{2}-\d{3}-\d{2}W\d$)|(^[A-D] [0-9]{3} [A-L] [0-9]{3}[A-P][0-9]{2}$)/;
  return re.test( s );
}

我只假设使用案例编号 1 的 #3 进行第一次验证,因为我不确定如何使用空格、破折号或任何内容都无效。

4

5 回答 5

2

你真的不想一次性构建一个大的正则表达式。它将难以阅读且难以维护。当你在坎昆度假,在海滩上啜饮玛格丽塔酒时,当你的开发人员同事不得不调试它时,他们会讨厌你。

所以我建议把它分解成清晰、有意义的块(你必须在这里使用你的判断:这是你的域)。也许是这样的。

var prefix = '([12]0[0-9] )';
var suffix = '( 0[0-9])';
// ? optionally matches the preceding item.
// And don't forget to escape backslashes when creating
// a regexp from a string.
var num1 = '\\d{2}-\\d{2}-\\d{3}-\\d{2}[- ]?W\\d';
var num2 = '[A-D] [0-9]{3} [A-L] [0-9]{3}[A-P][0-9]{2}';
var numbers = '(' + num1 + '|' + num2 + ')';
var pattern = '^(' + prefix + numbers + suffix + '|' + numbers + ')$';
// Instead of creating a large regexp literal all in
// one go, you can build up the regexp pattern from strings,
// and then use RegExp(pattern) to make a regexp instance.
var rx = RegExp(pattern);

现在您可以使用它rx来匹配您输入的数字。随意使用更有意义的变量名。

但不要只是把它留在那里。这段代码急需一些测试。

var testcases = [
    {
        name: 'Number 1',
        tests: [
            {input: '14-36-085-17 W6', expected: true},
            {input: '14-36-085-17-W6', expected: true},
            {input: '14-36-085-17W6', expected: true}
        ]
    },
    {
        name: 'Number 2',
        tests: [
            {input: 'D 096 H 094A15', expected: true}
        ]
    },
    {
        name: 'Number 3',
        tests: [
            {input: '100 14-36-085-17W6 00', expected: true},
            {input: '200 D 096 H 094A15 00', expected: true},
            {input: '100 14-36-085-17W6', expected: false},
            {input: '14-36-085-17W6 00', expected: false}
        ]
    }
];

让我们试试我们的正则表达式。我只是在 Chrome 的开发者控制台中运行这些测试(F12为此)。

testcases.forEach(function(testcase){
    console.log(testcase.name);
    testcase.tests.forEach(function(test){
        var result = rx.test(test.input);
        console.log(test.input + '  result: ' +
                (result ? 'match' : 'no match') +
                (result === test.expected ? ' [pass]' : ' [**FAIL**]'));
    });
    console.log('');
});

和输出。

    1号
    14-36-085-17 W6 结果:匹配 [通过]
    14-36-085-17-W6 结果:匹配 [通过]
    14-36-085-17W6 结果:匹配 [通过]

    2号
    D 096 H 094A15 结果:匹配 [通过]

    3 号
    100 14-36-085-17W6 00 结果:匹配 [通过]
    200 D 096 H 094A15 00 结果:匹配 [通过]
    100 14-36-085-17W6 结果:不匹配 [通过]
    14-36-085-17W6 00 结果:不匹配 [通过]

伟大的。进行测试让你有信心做出改变,并保证你在做的时候没有破坏任何东西。它让我相信我不会给你一个愚蠢的答案。如果您进行搜索,您会发现有许多自动化单元测试框架可以让您更轻松地编写测试。我给你的是一个基本的例子。但是,当您完全开始运行自动化测试时,就会获得巨大的胜利。之后的一切都是细化的。

顺便说一句,这些测试只是您在问题中提供的有效或无效示例(谢谢!)。我建议您找到更多示例并以此为基础。希望我已经给了你足够的指导,如果我所做的无论如何都不够,你可以从这里得到它。

对于正则表达式的答案,这似乎有点过头了,但我不能问心无愧地建议您使用巨大的正则表达式进行验证,而不推荐一些机器来保持事情的可管理性。


进一步阅读
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
http://en.wikipedia.org/wiki/Unit_testing

于 2013-07-08T22:21:55.070 回答
1

根据您对@SamuelReid 回答的评论中的要求,正则表达式会变得丑陋。当两个字符串要求依赖于彼此的开/关(在字符串的相对两侧)时,这会变得很困难。

正则表达式:

/^(?:(?:[12]0\d (?:\d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d|[A-D] \d{3} [A-L] \d{3}[A-P]\d{2}) 0\d)|(?:\d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d|[A-D] \d{3} [A-L] \d{3}[A-P]\d{2}))$/

格式精美/易于阅读的版本:

/^
  (?:
    (?:
      [12]0\d[ ]
      (?:
        \d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d
        |
        [A-D] \d{3} [A-L] \d{3}[A-P]\d{2}
      )
      [ ]0\d
    )
    |
    (?:
      \d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d
      |
      [A-D] \d{3} [A-L] \d{3}[A-P]\d{2}
    )
  )
$/x

[]在空格周围添加以强调它们,因为它们很重要并且在自由间距模式(x 标志)中丢失——js 不支持 AFAIK)

正如您从“更易于阅读的版本”中看到的那样,基本的正则表达式只需在其中一个表达式上添加[12]0\d[ ]和执行两次[ ]0\d

在正则表达式上看到它


如果它需要在字符串的中间匹配,只需在正则表达式的两端交换^$锚点:\b

带有边界的正则表达式\b而不是^and$

/\b(?:(?:[12]0\d (?:\d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d|[A-D] \d{3} [A-L] \d{3}[A-P]\d{2}) 0\d)|(?:\d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d|[A-D] \d{3} [A-L] \d{3}[A-P]\d{2}))\b/

于 2013-07-08T21:10:37.677 回答
1

/^([1-2]0[0-9] )?[0-9]{2}-[0-9]{2}-[0-9]{3}-[0-9]{2}[- ]?W[0-9]( 0[0-9])?$/

对于第一个,和

/^([1-2]0[0-9] )?[A-D] [0-9] [0-9]{3} [A-L] [0-9]{3}[A-P][0-9]{2}( 0[0-9])?$/

第二个。我对正则表达式不是很好,所以我完全有可能在某个地方搞砸了。

于 2013-07-08T20:57:45.850 回答
1

第一个数字类型可以用下面的表达式匹配,这和你已经拥有的非常相似:

/d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d/
                       ^^^^^ 
                       added

我正在使用字符集 ,[- ]?它可以选择匹配空格或连字符。

多余的字符

匹配左边:

/^[12]0\d /

和正确的部分:

/ 0\d$/

现在都在一起了:

/^(?:(?:[12]0\d )(?:\d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d|[A-D] \d{3} [A-L] \d{3}[A-P]\d{2})(?: 0\d)|(?:\d{2}-\d{2}-\d{3}-\d{2}[ -]?W\d|[A-D] \d{3} [A-L] \d{3}[A-P]\d{2}))$/

让我们清理一下:

var w1 = '\\d{2}-\\d{2}-\\d{3}-\\d{2}[ -]?W\\d',
w2 = '[A-D] \\d{3} [A-L] \\d{3}[A-P]\\d{2}',
words = '(?:' + w1 + '|' + w2 + ')',
prefix = '[12]0\\d ',
suffix = ' 0\\d',
re;

re = new RegExp('^(?:' + prefix + words + suffix + '|' + words + ')$');
于 2013-07-08T21:34:00.627 回答
0

这真的不是那么糟糕(尽管绝对是一个大的正则表达式)。这应该涵盖模式和开头或结尾的其他可能数字。

这是您需要的模式:

var re = new RegExp("^([1-2]0\\d )?(\\d{2}-\\d{2}-\\d{3}-\\d{2}[\- ]?W\\d|[A-D] \\d{3} [A-L] \\d{3}[A-P]\\d{2})( 0\\d)?$");

. . . 或者,或者:

var re = /^([1-2]0\d )?(\d{2}-\d{2}-\d{3}-\d{2}[\- ]?W\d|[A-D] \d{3} [A-L] \d{3}[A-P]\d{2})( 0\d)?$/

您的其余代码应该可以正常工作。

编辑:基于我对“全有或全无”的新理解,我更新了我的方法。. . 我会根据从常见模式构建的两个正则表达式模式进行两个测试。

var sCorePattern = "(\\d{2}-\\d{2}-\\d{3}-\\d{2}[\- ]?W\\d|[A-D] \\d{3} [A-L] \\d{3}[A-P]\\d{2})";
var sSecondaryPattern = "[1-2]0\\d " + sCorePattern + " 0\\d";

var regCorePattern = new RegExp("^" + sCorePattern + "$");
var regSecondaryPattern = new RegExp("^" + sSecondaryPattern + "$");

if (regCorePattern.test(s) || regSecondaryPattern.test(s)) {
    . . . do stuff . . .
}
else {
    . . . do other stuff . . .
}

对我来说,这是效率和重用的完美结合,同时又不牺牲可读性。:)

于 2013-07-08T22:11:39.477 回答