Regex to match exactly 5 numbers and one optional space
我最近需要创建一个正则表达式来检查javascript中的输入。输入的长度可以是5或6个字符,必须正好包含5个数字和一个可选的空格,可以是字符串中的任何位置。我一点都不懂雷吉斯,尽管我试图寻找更好的方法,但最终还是得到了这样的结果:
1 | (^\d{5}$)|(^ \d{5}$)|(^\d{5} $)|(^\d{1} \d{4}$)|(^\d{2} \d{3}$)|(^\d{3} \d{2}$)|(^\d{4} \d{1}$) |
这是我需要的,所以允许的输入是(如果0是任何数字)
1 2 3 4 5 6 7 | '00000' ' 00000' '0 0000' '00 000' '000 00' '0000 0' '00000 ' |
我怀疑这是实现与regex匹配的唯一方法,但我还没有找到一种更干净的方法。所以我的问题是,如何才能写得更好?
谢谢您。
编辑:所以,这是可能的!汤姆·洛德的回答满足了我对正则表达式的需求,所以我把它标为我问题的正确答案。
然而,在我发布这个问题后不久,我意识到我的想法不正确,因为项目中的其他输入很容易通过regex"验证",所以我立即假设我也可以用它验证这个输入。
结果我只能这样做:
1 2 3 4 5 | const validate = function(value) { const v = value.replace(/\s/g, '') const regex = new RegExp('^\\d{5}$'); return regex.test(v); } |
感谢大家的回答和想法!:)
edit2:我忘记提到一个可能非常重要的细节,那就是输入是有限的,所以用户最多只能输入6个字符。我很抱歉。
Note: Using a regular expression to solve this problem might not be
the best answer. As answered
below, it may be
easier to just count the digits and spaces with a simple function!However, since the question was asking for a regex answer, and in some
scenarios you may be forced to solve this with a regex (e.g. if
you're tied down to a certain library's implementation), the following
answer may be helpful:
此regex与正好包含5位数字的行匹配:
1 | ^(?=(\D*\d){5}\D*$) |
此regex匹配包含一个可选空格的行:
1 | ^(?=[^ ]* ?[^ ]*$) |
如果我们把它们放在一起,并且确保字符串只包含数字和空格(
1 | ^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$ |
您也可以在该模式的末尾使用
演示
说明:
此正则表达式正在使用lookaheads。这些是零宽度模式匹配器,这意味着模式的两个部分都"锚定"在字符串的开头。
\d 表示"任何数字",\d 表示"任何非数字"。表示"空间", [^ ] 表示"任何非空间"。\D*\d 被重复5次,以确保字符串中正好有5位数字。
下面是一个实际中的正则表达式的可视化:
请注意,如果您实际上希望"可选空间"包括选项卡之类的内容,那么您可以使用
更新:由于这个问题似乎得到了相当多的牵引力,我想澄清一些关于这个答案的问题。
对于我上面的答案,有几个"简单"的变体解决方案,例如:
1 2 3 4 5 6 7 8 | // 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个字符,那么即使这样也足够:
1 | ^(?:\d{5}|\d* \d*)$ |
因此,考虑到这一点,您为什么要对类似的问题使用原始的解决方案呢?因为它是通用的。再看一下我的原始答案,用空格重新书写:
1 2 3 4 | ^ (?=(\D*\d){5}\D*$) # Must contain exactly 5 digits (?=[^ ]* ?[^ ]*$) # Must contain 0 or 1 spaces [\d ]*$ # Must contain ONLY digits and spaces |
这种使用连续look a heads的模式可以在各种场景中使用,以编写高度结构化且(可能令人惊讶)易于扩展的模式。
例如,假设规则已更改,您现在想要匹配2-3个空格、1个
1 2 3 4 5 | ^ (?=(\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 |
…所以总的来说,有"更简单"的regex解决方案,而且很可能是一个更好的非regex解决方案来解决OP的特定问题。但我提供的是一个通用的、可扩展的设计模式,用于匹配这种类型的模式。
我建议首先检查五个数字
结合这些部分表达可得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
或者通过以下方式单独匹配部分表达式:
1 | /^\d{5}$/.test(input) || input.length == 6 && /^\d* \d*$/.test(input) |
这对我来说更直观,是O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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; } |
下面是一个简单的regex来完成这项工作:
1 | ^(?=[\d ]{5,6}$)\d*\s?\d*$ |
说明:
^断言字符串开头的位置
正面展望(?= [d] {5,6}$)
断言下面的regex匹配
匹配下面列表中的单个字符[d]5,6
5,6量词-匹配5到6次,尽可能多次,根据需要反馈(贪心)
D匹配一个数字(等于[0-9])字面匹配字符(区分大小写)
$断言字符串末尾的位置 D*匹配一个数字(等于[0-9])
- 量词-在零和无限次之间匹配,尽可能多次,根据需要反馈(贪婪)
s匹配任何空白字符(等于[
fv])
D*匹配一个数字(等于[0-9])
- 量词-在零和无限次之间匹配,尽可能多次,根据需要反馈(贪婪)
$断言字符串末尾的位置
你可以把它分成两半:
1 2 3 4 | var input = '0000 '; if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, ''))) console.log('Match'); |
这就是我不使用regex的方式:
1 2 3 4 5 | string => [...string].reduce( ([spaces,digits], char) => [spaces += char == ' ', digits += /\d/.test(char)], [0,0] ).join(",") =="1,5"; |
1 2 3 4 | string="12345"; if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){ alert("valid"); } |
你可以简单地检查长度,如果它是一个有效的数字…