正则表达式匹配恰好3个相同连续数字

6
早上好大家,
我想要创建一个正则表达式,用于匹配连续出现的三个相同数字。它只应该匹配连续出现的三个数字(以空格分隔),这些数字应该是相同的。如果出现少于或多于三个相同数字,则输出应为false。
我尝试了这个正则表达式/.*(\d+) \1 \1(?!(\s\1))/
console.log(/.*(\d+) \1 \1(?!(\s\1))/.test('I am 42 42 4 hey yoo')); //false --> Correct
 
console.log(/.*(\d+) \1 \1(?!(\s\1))/.test('I am 42 42 42 hey yoo')); //true --> Correct

console.log(/.*(\d+) \1 \1(?!(\s\1))/.test('I am 42 42 42 4 hey yoo')); //true --> Correct

console.log(/.*(\d+) \1 \1(?!(\s\1))/.test('I am 42 42 42 42 hey yoo')); //true --> this output should be false since there are 4 same consecutive digits

有什么建议吗?

这个回答解决了你的问题吗?用于检查4个连续数字的正则表达式 - Mark
@马克,要修改链接的答案以适应这个问题的实际情况并不是很明显(甚至相当具有挑战性),因为我们讨论的不是数字,而是数值。 - markalex
2
foo 42 42 42 bar 42 42 42 42这个怎么样?应该匹配还是不匹配? - InSync
禁止@InSync在这里使用只有前瞻的正则表达式来匹配四个或更多的样本:^(?!.*?(?: |^)(\d+)(?: \1){3}(?!\S)).*?(?: |^)(\d+)(?: \2){2}(?!\S) - bobble bubble
@Thefourthbird和我的答案有不同的假设。例如,他匹配字符串"I am^42 42 42 hey yoo",而我不匹配(因为我要求第一个"42"前面有一个空格或者在字符串的开头)。两组假设都不正确;这取决于你想要的方式。 - Cary Swoveland
2个回答

3
我假设三个相同的数字字符串之间用一个空格分隔,这个三个字符串中的第一个要么在字符串的开头,要么前面有一个不是同样字符串的空格;而这个三个字符串中的最后一个要么在字符串的结尾,要么后面有一个不是同样字符串的空格。
你可以尝试匹配以下正则表达式。
(?: |^)(\d+)(?<!(?: |^)\1 \1)(?: \1){2}(?![^ ]| \1(?: |$))

演示

正则表达式可以分解如下。(或者,将光标悬停在链接上的每个表达式部分上,以获取其功能的解释。)

(?: |^)     # match a space or the beginning of the string
(\d+)       # match one or more digits and save to capture group 1
(?<!        # begin a negative lookbehind
  (?: |^)    # match a space or the beginning of the string
  \1 \1      # match the content of capture group 1 twice, separated by a space
)           # end the negative lookbehind
(?: \1)     # match a space followed by the content of capture group 1
{2}         # execute the preceding non-capture group twice
(?!         # begin a negative lookahead
  [^ ]        # match a character other than a space
  |           # or
   \1         # match a space followed by the content of capture group 1
  (?: |$)     # match a space or the end of the string
)           # end the negative lookahead

请注意,(?: .... ) 表示一个非捕获组。

你的正则表达式可以通过用\b替换(?: |^)(?: |$)来大大简化。 - InSync
@InSync,这将导致”*1 1 1”被匹配(例如),这与我对需求的声明前提不一致。 - Cary Swoveland
@CarySwoveland 嗨Cary,非常感谢啊。你的正则表达式成功了。顺便说一下,如果你有时间,能不能告诉我我的正则表达式哪里出错了 /.*(\d+) \1 \1(?!(\s\1))/。我不明白为什么我的正则表达式不起作用。 - Rol Co
@CarySwoveland 嗨Cary,非常感谢啊。你的正则表达式成功了。顺便说一下,如果你有时间的话,能不能告诉我我的正则表达式哪里有问题 /.*(\d+) \1 \1(?!(\s\1))/。我不明白为什么我的正则表达式不起作用。 - undefined
Rol Co,我看到了几个问题。首先,如果字符串是"12 12 12 12",你的正则表达式会匹配成功,因为捕获组会匹配第二个"12"。你需要做一些防止捕获组前面出现相同内容的处理。其次,字符串"12 12 12 123"应该被匹配,但是你的正则表达式没有匹配成功。根据假设,/.*(\d+) \1 \1(?!\s\1\b)/可能足以解决第二个问题。顺便说一下,我看不出为什么要将\s\1放在一个捕获组中。 - Cary Swoveland

2
在你的模式中,你混合了空格和\s,它匹配一个空白字符,也可以匹配换行符。
你可以检查第一个捕获组的值(\d+)是否不是前面有相同的值。
为了防止部分匹配,可以使用带有单词边界的版本。
\b(\d+)\b(?<!\b\1 \1)(?: \1){2}\b(?! \1\b)

正则表达式演示

模式匹配:

  • \b(\d+)\b 捕获第一组,匹配一个或多个数字,位于单词边界之间
  • (?<!\b\1 \1) 负向回顾,断言此数字之前没有相同的数字
  • (?: \1){2}\b 重复两次空格和第一组的值,以单词边界结尾
  • (?! \1\b) 负向预查,断言右侧不是第一组的值,后面跟着一个单词边界

const regex = /\b(\d+)\b(?<!\b\1 \1)(?: \1){2}\b(?! \1\b)/;

console.log(regex.test('I am 42 42 4 hey yoo')); //false --> Correct
 
console.log(regex.test('I am 42 42 42 hey yoo')); //true --> Correct

console.log(regex.test('I am 42 42 42 4 hey yoo')); //true --> Correct

console.log(regex.test('I am 42 42 42 42 hey yoo')); //true --> this output should be false since there are 4 same consecutive digits


或者如果不支持向后查找,您可以匹配3次相同的数字,并在第2组中选择性地匹配重复数字的其余部分。
在结果中,您可以检查是否没有匹配,或者捕获第2组的值:
\b(\d+)(?: \1){2}( \1)*\b

正则表达式演示

const regex = /\b(\d+)(?: \1){2}( \1)*\b/;
[
  'I am 42 42 4 hey yoo',
  'I am 42 42 42 hey yoo',
  'I am 42 42 42 4 hey yoo',
  'I am 42 42 42 42 hey yoo'
].forEach(s => {
  const m = s.match(regex);
  console.log(`${s} --> ${!(!m || m[2])}`);
})


@InSync 这个模式将会有一个不同的匹配 https://regex101.com/r/BjPjcD/1 同样,使用一个单独的感叹号 !(m && !m[2]) 将会得到相反的结果。 - The fourth bird
@InSync 不,m[2] 表示有一个第二组的值,所以有3个相同的数字。 - The fourth bird
1
@InSync 在这种情况下,您可以将其写为\b(\d+)(?: \1){2}( \1)*\b并检查第二个分组的值。 - The fourth bird
1
我把我的视为你的延伸,所以请更新你的回答。 - InSync
1
嗨 @Thefourthbird,非常感谢。你的正则表达式 \b(\d+)\b(?<!\b\1 \1)(?: \1){2}\b(?! \1\b) 成功地起作用了。真的很感激你的解决方案,伙计。 - Rol Co
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接