正则表达式恰好匹配5个数字和一个可选空格

时间:2017-06-09 16:09:22

标签: javascript regex validation

我最近需要创建一个正则表达式来检查JavaScript中的输入。输入可以是5或6个字符长,并且必须包含正好5个数字和一个可选空格,它们可以是字符串中的任何位置。我根本不是正则表达式,即使我尝试寻找更好的方法,我最终得到了这个:

(^\d{5}$)|(^ \d{5}$)|(^\d{5} $)|(^\d{1} \d{4}$)|(^\d{2} \d{3}$)|(^\d{3} \d{2}$)|(^\d{4} \d{1}$)  

这就是我需要的,所以允许的输入是(如果0是任何数字)

'00000'  
' 00000'  
'0 0000'  
'00 000'  
'000 00'  
'0000 0'  
'00000 '

我怀疑这是实现与正则表达式匹配的唯一方法,但我还没有找到一种方法以更清洁的方式来实现。所以我的问题是,如何更好地写出来?

谢谢。

编辑:
所以,这是可能的! Tom Lord的回答用正则表达式做了我需要的,所以我把它标记为我的问题的正确答案。

然而,在我发布这个问题之后不久,我意识到我的想法不对,因为项目中的每个其他输入都很容易用正则表达式“验证”,我立即假设我可以用它来验证这个。

原来我可以这样做:

const validate = function(value) {
    const v = value.replace(/\s/g, '')
    const regex = new RegExp('^\\d{5}$');
    return regex.test(v);
}  

谢谢大家的精彩答案和想法! :)

Edit2:我忘了提到一个可能非常重要的细节,即输入是有限的,因此用户最多只能输入6个字符。道歉。

7 个答案:

答案 0 :(得分:19)

  

注意:使用正则表达式解决此问题可能不是   最好的答案。 As answered below,它可能是   用简单的函数更容易计算数字和空格!

     

然而,因为问题是要求正则表达式的答案,在某些情况下   您可能强制使用正则表达式解决此问题的方案(例如,如果   你被束缚到某个图书馆的实施),以下内容   答案可能会有所帮助:

此正则表达式匹配包含5位数字的行:

^(?=(\D*\d){5}\D*$)

此正则表达式匹配包含一个可选空格的行:

^(?=[^ ]* ?[^ ]*$)

如果我们将它们放在一起,并确保字符串包含数字和空格[\d ]*$),我们得到:

^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$

您也可以在该模式的末尾使用[\d ]{5,6}代替[\d ]*,效果相同。

Demo

<强>解释

此正则表达式使用lookaheads。这些是零宽度模式匹配器,这意味着模式的两个部分都“锚定”到字符串的开头。

  • \d表示“任意数字”,\D表示“任何非数字”。

  • 表示“空格”,[^ ]表示“任何非空格”。

  • \D*\d重复5次,以确保字符串中只有5位数字。

以下是正则表达式的可视化:

regex visualisation

请注意,如果您确实希望“可选空间”包含标签等内容,则可以使用\s\S

更新:由于这个问题似乎引起了很大的关注,我想澄清一下这个答案。

上面的答案中有几个“更简单”的变体解决方案,例如:

// Only look for digits and spaces, not "non-digits" and "non-spaces":
^(?=( ?\d){5} *$)(?=\d* ?\d*$)

// Like above, but also simplifying the second lookahead:
^(?=( ?\d){5} *$)\d* ?\d*

// Or even splitting it into two, simpler, problems with an "or" operator: 
^(?:\d{5}|(?=\d* \d*$).{6})$

上述每一行的演示:1 2 3

或者,如果我们 假设 该字符串不超过6个字符,那么即使这样就足够了:

^(?:\d{5}|\d* \d*)$

因此,考虑到这一点,为什么可能您想要使用原始解决方案,以解决类似问题?因为它是通用。再看看我的原始答案,用free-spacing重写:

^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=[^ ]* ?[^ ]*$)  # Must contain 0 or 1 spaces
[\d ]*$            # Must contain ONLY digits and spaces

这种使用连续预测的模式可以用in various scenarios来编写高度结构化的模式,并且(可能令人惊讶地)易于扩展。

例如,假设规则已更改,您现在想要匹配2-3个空格,1 .和任意数量的连字符。实际上很容易更新正则表达式:

^
(?=(\D*\d){5}\D*$)       # Must contain exactly 5 digits
(?=([^ ]* ){2,3}[^ ]*$)  # Must contain 2 or 3 spaces
(?=[^.]*\.[^.]*$)        # Must contain 1 period
[\d .-]*$   # Must contain ONLY digits, spaces, periods and hyphens

...总而言之,“更简单”的正则表达式解决方案,并且很可能是针对OP特定问题的更好的非正则表达式解决方案。但我提供的是一种通用的,可扩展的设计模式,用于匹配这种性质的模式。

答案 1 :(得分:8)

我建议首先检查五个数字^\d{5}$或者预先查找六个字符^(?=\d* \d*$)中数字.{6}$之间的单个空格。

合并这些部分表达式会产生^\d{5}$|^(?=\d* \d*$).{6}$

let regex = /^\d{5}$|^(?=\d* \d*$).{6}$/;

console.log(regex.test('00000'));   // true
console.log(regex.test(' 00000'));  // true
console.log(regex.test('00000 '));  // true
console.log(regex.test('00 000'));  // true
console.log(regex.test('  00000')); // false
console.log(regex.test('00000  ')); // false
console.log(regex.test('00  000')); // false
console.log(regex.test('00 0 00')); // false
console.log(regex.test('000 000')); // false
console.log(regex.test('0000'));    // false
console.log(regex.test('000000'));  // false
console.log(regex.test('000 0'));   // false
console.log(regex.test('000 0x'));  // false
console.log(regex.test('0000x0'));  // false
console.log(regex.test('x00000'));  // false

或者通过例如:

分别匹配部分表达式
/^\d{5}$/.test(input) || input.length == 6 && /^\d* \d*$/.test(input)

答案 2 :(得分:7)

这对我来说似乎更直观,而且是O(n)

function isInputValid(input) {
    const length = input.length;
    if (length != 5 && length != 6) {
        return false;
    }

    let spaceSeen = false;
    let digitsSeen = 0;
    for (let character of input) {
        if (character === ' ') {
            if (spaceSeen) {
                return false;
            }
            spaceSeen = true;
        }
        else if (/^\d$/.test(character)) {
            digitsSeen++;
        }
        else {
            return false;
        }
    }

    return digitsSeen == 5;
}

答案 3 :(得分:1)

你可以把它分成两半:

&#13;
&#13;
var input = '0000 ';

if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, '')))
  console.log('Match');
&#13;
&#13;
&#13;

答案 4 :(得分:1)

这是一个简单的正则表达式来完成这项工作:

^(?=[\d ]{5,6}$)\d*\s?\d*$

说明:

^在字符串

的开头处断言位置

积极前瞻(?= [\ d] {5,6} $)

断言下面的正则表达式匹配

匹配[\ d] {5,6}

下方列表中的单个字符

{5,6}量词 - 匹配5至6次,尽可能多次,根据需要回馈(贪婪)

\ d匹配一个数字(等于[0-9])   字面匹配字符(区分大小写)

$断言字符串末尾的位置 \ d *匹配一个数字(等于[0-9])

  • 量词 - 在零和无限次之间匹配,尽可能多次,根据需要回馈(贪婪)

\ s匹配任何空白字符(等于[\ r \ n \ t \ f \ v])

\ d *匹配一个数字(等于[0-9])

  • 量词 - 在零和无限次之间匹配,尽可能多次,根据需要回馈(贪婪)

$断言字符串末尾的位置

答案 5 :(得分:0)

string="12345 ";
if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){
  alert("valid");
}

您只需检查长度以及是否有效数字......

答案 6 :(得分:0)

如果没有正则表达式,我就会这样做:

string => [...string].reduce(
    ([spaces,digits], char) =>
        [spaces += char == ' ', digits += /\d/.test(char)],
    [0,0]
).join(",") == "1,5";