I recently needed to create a regular expression to check input in JavaScript. The input could be 5 or 6 characters long and had to contain exactly 5 numbers and one optional space, which could be anywhere in the string. I am not regex-savvy at all and even though I tried looking for a better way, I ended up with this:
我最近需要创建一个正则表达式来检查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}$)
This does what I need, so the allowed inputs are (if 0 is any number)
这就是我需要的,所以允许的输入是(如果0是任意数)
'00000'
' 00000'
'0 0000'
'00 000'
'000 00'
'0000 0'
'00000 '
I doubt that this is the only way to achieve such matching with regex, but I haven't found a way to do it in a cleaner way. So my question is, how can this be written better?
我怀疑这是否是实现与regex匹配的唯一方法,但我还没有找到一种更干净的方法。我的问题是,怎么写得更好?
Thank you.
谢谢你!
Edit:
So, it is possible! Tom Lord's answer does what I needed with regular expressions, so I marked it as a correct answer to my question.
编辑:所以,这是可能的!汤姆·洛德的回答符合我对正则表达式的要求,所以我把它标记为我的问题的正确答案。
However, soon after I posted this question, I realized that I wasn't thinking right, since every other input in the project was easily 'validatable' with regex, I was immediately assuming I could validate this one with it as well.
然而,在我发布这个问题后不久,我就意识到我的想法是错误的,因为项目中的每个其他输入都很容易用regex进行“验证”,我立即假设我也可以用它来验证这个输入。
Turns out I could just do this:
我可以这样做:
const validate = function(value) {
const v = value.replace(/\s/g, '')
const regex = new RegExp('^\\d{5}$');
return regex.test(v);
}
Thank you all for the cool answers and ideas! :)
感谢大家的冷静回答和想法!:)
Edit2: I forgot to mention a possibly quite important detail, which is that the input is limited, so the user can only enter up to 6 characters. My apologies.
Edit2:我忘了提到一个可能很重要的细节,即输入是有限的,所以用户最多只能输入6个字符。我的歉意。
7 个解决方案
#1
16
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的答案,并且在某些情况下,您可能*使用regex来解决这个问题(例如,如果您被绑定到某个库的实现),下面的答案可能是有用的:
This regex matches lines containing exactly 5 digits:
此regex匹配恰好包含5位数字的行:
^(?=(\D*\d){5}\D*$)
This regex matches lines containing one optional space:
这个regex匹配包含一个可选空间的行:
^(?=[^ ]* ?[^ ]*$)
If we put them together, and also ensure that the string contains only digits and spaces ([\d ]*$
), we get:
如果我们将它们放在一起,并确保字符串只包含数字和空格([\d]*$),我们得到:
^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$
You could also use [\d ]{5,6}
instead of [\d ]*
on the end of that pattern, to the same effect.
您还可以在模式的末尾使用[\d]{5,6}而不是[\d]*来达到相同的效果。
演示
Explanation:
解释:
This regular expression is using lookaheads. These are zero-width pattern matchers, which means both parts of the pattern are "anchored" to the start of the string.
这个正则表达式使用的是lookahead。这些是零宽度的模式匹配器,这意味着模式的两个部分都“锚定”在字符串的开头。
-
\d
means "any digit", and\D
means "any non-digit".\d表示“任何数字”,\d表示“任何非数字”。
-
means "space", and
[^ ]
means "any non-space".意思是“空间”,[^]意味着“任何”进行技术改造。
-
The
\D*\d
is being repeated 5 times, to ensure exactly 5 digits are in the string.\D*\ D被重复5次,以确保正确的5位数字在字符串中。
Here is a visualisation of the regex in action:
以下是regex的可视化操作:
Note that if you actually wanted the "optional space" to include things like tabs, then you could instead use \s
and \S
.
注意,如果您确实想要“可选空间”包含标签之类的内容,那么您可以使用\s和\s。
Update: Since this question appears to have gotten quite a bit of traction, I wanted to clarify something about this answer.
更新:由于这个问题似乎得到了相当多的关注,我想澄清一些关于这个答案的事情。
There are several "simpler" variant solutions to my answer above, such as:
我上面的回答有几个“更简单”的变体解决方案,比如:
// 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})$
Demos of each line above: 1 2 3
上面每一行的演示:1 2 3
Or even, if we can assume that the string is no more than 6 characters then even just this is sufficient:
甚至,如果我们假设字符串不超过6个字符,那么这个就足够了:
^(?:\d{5}|\d* \d*)$
So with that in mind, why might you want to use the original solution, for similar problems? Because it's generic. Look again at my original answer, re-written with free-spacing:
考虑到这一点,为什么要使用原始的解决方案,来解决类似的问题呢?因为它是通用的。再看我最初的答案,用*间距重写:
^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=[^ ]* ?[^ ]*$) # Must contain 0 or 1 spaces
[\d ]*$ # Must contain ONLY digits and spaces
This pattern of using successive look-aheads can be used in various scenarios, to write patterns that are highly structured and (perhaps surprisingly) easy to extend.
这种使用连续查找的模式可以在各种场景中使用,来编写高度结构化的模式,并且(可能令人惊讶地)易于扩展。
For example, suppose the rules changed and you now wanted to match 2-3 spaces, 1 .
and any number of hyphens. It's actually very easy to update the regex:
例如,假设规则改变了,现在需要匹配2-3个空格,1。和任意数量的连字符。更新regex其实很容易:
^
(?=(\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
...So in summary, there are "simpler" regex solutions, and quite possibly a better non-regex solution to OP's specific problem. But what I have provided is a generic, extensible design pattern for matching patterns of this nature.
…综上所述,有“更简单”的regex解决方案,很有可能是更好的非regex解决方案来解决OP的特定问题。但是我提供的是一个通用的、可扩展的设计模式,用于匹配这种性质的模式。
#2
8
I suggest to first check for exactly five numbers ^\d{5}$
OR look ahead for a single space between numbers ^(?=\d* \d*$)
among six characters .{6}$
.
我建议首先检查完全五个数字^ \ d { 5 } $或展望未来数字^(之间一个空格?=\d* \d*$)在六个字符之间。{6}$。
Combining those partial expressions yields ^\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
Alternatively match the partial expressions separately via e.g.:
也可将部分表达式单独匹配,例如:
/^\d{5}$/.test(input) || input.length == 6 && /^\d* \d*$/.test(input)
#3
7
This seems more intuitive to me and is O(n)
这对我来说更直观,是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;
}
#4
1
You can split it in half:
你可以把它一分为二:
var input = '0000 ';
if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, '')))
console.log('Match');
#5
1
Here's a simple regex to do the job:
这里有一个简单的regex来完成这项工作:
^(?=[\d ]{5,6}$)\d*\s?\d*$
Explanation:
解释:
^ asserts position at start of the string
^断言在字符串的开始位置
Positive Lookahead (?=[\d ]{5,6}$)
积极的超前(?= \[d]{ 5、6 } $)
Assert that the Regex below matches
断言下面的Regex匹配。
Match a single character present in the list below [\d ]{5,6}
匹配下面列表中的单个字符[\d]{5,6}
{5,6} Quantifier — Matches between 5 and 6 times, as many times as possible, giving back as needed (greedy)
{5,6}量词——匹配5到6次,尽可能多地匹配,根据需要返回(贪婪)
\d matches a digit (equal to [0-9]) matches the character literally (case sensitive)
\d匹配数字(等于[0-9])匹配字符(区分大小写)
$ asserts position at the end of the string \d* matches a digit (equal to [0-9])
字符串\d*末尾的$ assert位置匹配一位数字(等于[0-9])
- Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
- 量词——在零到无限次之间匹配,尽可能多地匹配,根据需要返回(贪婪)
\s matches any whitespace character (equal to [\r\n\t\f\v ])
\s匹配任何空格字符(等于[\r\n\t\f\v])
\d* matches a digit (equal to [0-9])
\d*匹配一个数字(等于[0-9])
- Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
- 量词——在零到无限次之间匹配,尽可能多地匹配,根据需要返回(贪婪)
$ asserts position at the end of the string
$断言字符串末尾的位置
#6
0
string="12345 ";
if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){
alert("valid");
}
You could simply check the length and if its a valid number...
你可以检查长度,如果它是一个有效的数字……
#7
0
This is how I would do it without regex:
如果没有regex,我将这样做:
string => [...string].reduce(
([spaces,digits], char) =>
[spaces += char == ' ', digits += /\d/.test(char)],
[0,0]
).join(",") == "1,5";
#1
16
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的答案,并且在某些情况下,您可能*使用regex来解决这个问题(例如,如果您被绑定到某个库的实现),下面的答案可能是有用的:
This regex matches lines containing exactly 5 digits:
此regex匹配恰好包含5位数字的行:
^(?=(\D*\d){5}\D*$)
This regex matches lines containing one optional space:
这个regex匹配包含一个可选空间的行:
^(?=[^ ]* ?[^ ]*$)
If we put them together, and also ensure that the string contains only digits and spaces ([\d ]*$
), we get:
如果我们将它们放在一起,并确保字符串只包含数字和空格([\d]*$),我们得到:
^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$
You could also use [\d ]{5,6}
instead of [\d ]*
on the end of that pattern, to the same effect.
您还可以在模式的末尾使用[\d]{5,6}而不是[\d]*来达到相同的效果。
演示
Explanation:
解释:
This regular expression is using lookaheads. These are zero-width pattern matchers, which means both parts of the pattern are "anchored" to the start of the string.
这个正则表达式使用的是lookahead。这些是零宽度的模式匹配器,这意味着模式的两个部分都“锚定”在字符串的开头。
-
\d
means "any digit", and\D
means "any non-digit".\d表示“任何数字”,\d表示“任何非数字”。
-
means "space", and
[^ ]
means "any non-space".意思是“空间”,[^]意味着“任何”进行技术改造。
-
The
\D*\d
is being repeated 5 times, to ensure exactly 5 digits are in the string.\D*\ D被重复5次,以确保正确的5位数字在字符串中。
Here is a visualisation of the regex in action:
以下是regex的可视化操作:
Note that if you actually wanted the "optional space" to include things like tabs, then you could instead use \s
and \S
.
注意,如果您确实想要“可选空间”包含标签之类的内容,那么您可以使用\s和\s。
Update: Since this question appears to have gotten quite a bit of traction, I wanted to clarify something about this answer.
更新:由于这个问题似乎得到了相当多的关注,我想澄清一些关于这个答案的事情。
There are several "simpler" variant solutions to my answer above, such as:
我上面的回答有几个“更简单”的变体解决方案,比如:
// 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})$
Demos of each line above: 1 2 3
上面每一行的演示:1 2 3
Or even, if we can assume that the string is no more than 6 characters then even just this is sufficient:
甚至,如果我们假设字符串不超过6个字符,那么这个就足够了:
^(?:\d{5}|\d* \d*)$
So with that in mind, why might you want to use the original solution, for similar problems? Because it's generic. Look again at my original answer, re-written with free-spacing:
考虑到这一点,为什么要使用原始的解决方案,来解决类似的问题呢?因为它是通用的。再看我最初的答案,用*间距重写:
^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=[^ ]* ?[^ ]*$) # Must contain 0 or 1 spaces
[\d ]*$ # Must contain ONLY digits and spaces
This pattern of using successive look-aheads can be used in various scenarios, to write patterns that are highly structured and (perhaps surprisingly) easy to extend.
这种使用连续查找的模式可以在各种场景中使用,来编写高度结构化的模式,并且(可能令人惊讶地)易于扩展。
For example, suppose the rules changed and you now wanted to match 2-3 spaces, 1 .
and any number of hyphens. It's actually very easy to update the regex:
例如,假设规则改变了,现在需要匹配2-3个空格,1。和任意数量的连字符。更新regex其实很容易:
^
(?=(\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
...So in summary, there are "simpler" regex solutions, and quite possibly a better non-regex solution to OP's specific problem. But what I have provided is a generic, extensible design pattern for matching patterns of this nature.
…综上所述,有“更简单”的regex解决方案,很有可能是更好的非regex解决方案来解决OP的特定问题。但是我提供的是一个通用的、可扩展的设计模式,用于匹配这种性质的模式。
#2
8
I suggest to first check for exactly five numbers ^\d{5}$
OR look ahead for a single space between numbers ^(?=\d* \d*$)
among six characters .{6}$
.
我建议首先检查完全五个数字^ \ d { 5 } $或展望未来数字^(之间一个空格?=\d* \d*$)在六个字符之间。{6}$。
Combining those partial expressions yields ^\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
Alternatively match the partial expressions separately via e.g.:
也可将部分表达式单独匹配,例如:
/^\d{5}$/.test(input) || input.length == 6 && /^\d* \d*$/.test(input)
#3
7
This seems more intuitive to me and is O(n)
这对我来说更直观,是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;
}
#4
1
You can split it in half:
你可以把它一分为二:
var input = '0000 ';
if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, '')))
console.log('Match');
#5
1
Here's a simple regex to do the job:
这里有一个简单的regex来完成这项工作:
^(?=[\d ]{5,6}$)\d*\s?\d*$
Explanation:
解释:
^ asserts position at start of the string
^断言在字符串的开始位置
Positive Lookahead (?=[\d ]{5,6}$)
积极的超前(?= \[d]{ 5、6 } $)
Assert that the Regex below matches
断言下面的Regex匹配。
Match a single character present in the list below [\d ]{5,6}
匹配下面列表中的单个字符[\d]{5,6}
{5,6} Quantifier — Matches between 5 and 6 times, as many times as possible, giving back as needed (greedy)
{5,6}量词——匹配5到6次,尽可能多地匹配,根据需要返回(贪婪)
\d matches a digit (equal to [0-9]) matches the character literally (case sensitive)
\d匹配数字(等于[0-9])匹配字符(区分大小写)
$ asserts position at the end of the string \d* matches a digit (equal to [0-9])
字符串\d*末尾的$ assert位置匹配一位数字(等于[0-9])
- Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
- 量词——在零到无限次之间匹配,尽可能多地匹配,根据需要返回(贪婪)
\s matches any whitespace character (equal to [\r\n\t\f\v ])
\s匹配任何空格字符(等于[\r\n\t\f\v])
\d* matches a digit (equal to [0-9])
\d*匹配一个数字(等于[0-9])
- Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
- 量词——在零到无限次之间匹配,尽可能多地匹配,根据需要返回(贪婪)
$ asserts position at the end of the string
$断言字符串末尾的位置
#6
0
string="12345 ";
if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){
alert("valid");
}
You could simply check the length and if its a valid number...
你可以检查长度,如果它是一个有效的数字……
#7
0
This is how I would do it without regex:
如果没有regex,我将这样做:
string => [...string].reduce(
([spaces,digits], char) =>
[spaces += char == ' ', digits += /\d/.test(char)],
[0,0]
).join(",") == "1,5";