正则表达式使用可选的前后字符串验证多种格式

时间:2013-07-08 20:38:46

标签: javascript regex

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

有效值:

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个附加字符中,这些是规则:

  • 1st - 总是1或2
  • 第二名 - 总是0
  • 3rd - 0 to 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,因为我不确定如何将空格,破折号或任何内容视为有效。

5 个答案:

答案 0 :(得分: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('');
});

输出。

    Number 1
    14-36-085-17 W6  result: match [pass]
    14-36-085-17-W6  result: match [pass]
    14-36-085-17W6  result: match [pass]

    Number 2
    D 096 H 094A15  result: match [pass]

    Number 3
    100 14-36-085-17W6 00  result: match [pass]
    200 D 096 H 094A15 00  result: match [pass]
    100 14-36-085-17W6  result: no match [pass]
    14-36-085-17W6 00  result: no match [pass]

大。通过测试可以让您有信心进行更改, 并保证你没有破坏任何东西 做。它让我有信心,我不会给你一个 duff回答。如果你搜索你会看到有很多 可用的自动化单元测试框架 写测试更容易。我给你的是一个基本的 例。但是当你开始跑步时,就会获得巨大的胜利 自动化测试;之后的一切都是精致的。

顺便说一句,这些测试只是您提供的示例 在问题中有效或无效(谢谢!)。 ID 建议您找到更多示例并以此为基础。 希望我已经给你足够的指示,你能够 如果我所做的事情没有结果,那就从这里拿走它 以任何方式充足。

对于正则表达式的回答,这似乎有点过分了,但是 我不能明确表示你使用了一个巨大的 regexp用于验证而不推荐一些机器 让事情变得易于管理。

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

答案 1 :(得分: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])?$/

第二个。我对正则表达式并不好,所以我完全有可能把某些东西搞砸了。

答案 2 :(得分: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即可完成两次。

See it live on regexpal


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

使用\b边界代替^$

的正则表达式

/\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/

答案 3 :(得分: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 + ')$');

答案 4 :(得分: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 . . .
}

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