使用正则表达式匹配字符串的开头和结尾相同的字符

37

我想匹配字符串的开头和结尾字符是相同的元音字母。我的正则表达式在大多数情况下都有效,但在某些情况下会失败:

var re = /([aeiou]).*\1/;
re.test(str);

示例输入:

  • abcde,输出 - false(有效)
  • abcda,输出 - true(有效)
  • aabcdaa,输出 - true(有效)
  • aeqwae,输出 - true(无效)
  • ouqweru,输出 - true(无效)

在哪些情况下它会失败? - Lazar Ljubenović
可能是 匹配第一个和最后一个字符的正则表达式 的重复问题。 - Redu
1
\1 是什么意思? - FluffyBeing
\1 匹配与第一个捕获组最近匹配的相同文本 - KeshavDulal
4个回答

70

你需要在字符串中添加锚点。

例如,当你有:

aeqwae

您说输出结果是true,但是它不是有效的,因为ae不同。嗯,正则表达式只匹配前一个字符(在e之前),即a。因此,匹配是有效的。所以,您会得到这个:

[aeqwa]e
在括号中的字符串是实际匹配并导致返回值为 true 的原因。

如果你将正则表达式更改为以下内容:

/^([aeiou]).*\1$/
通过添加^,您告诉它匹配的开头必须是字符串的开头,通过添加$,您告诉它匹配的结尾必须是字符串的结尾。这样,如果有匹配项,则必须匹配整个字符串,这意味着aeqwae将不再被匹配。
一个很好的测试正则表达式的工具是Regex101。试试吧! 注意:根据您的输入,您可能需要设置全局(g)或多行(m)标志。全局标志可以防止正则表达式在第一次匹配后返回。多行标志使得^$匹配每一行的开头和结尾(而不是整个字符串的开头和结尾)。当我使用您的输入进行测试时,我都使用了它们。

上面答案中唯一不清楚的是,如何重复使用与开头匹配的值放在结尾?... 那么\1是什么意思? - Beezer
捕获组。 (正则表达式) 括号将它们之间的正则表达式分组。它们将匹配的文本捕获到一个编号组中,可以使用编号反向引用重复使用。所以我猜我自己回答了我的问题。感谢您提供如此棒的答案。现在,继续向前了解(g)(m)等内容。 - Beezer
为了理解 \1 的实际作用,您可能想查看此链接:https://javascript.info/regexp-backreferences#backreference-by-number-n - Maulik Pipaliya Joyy
你可能需要添加另一个 \ 进行转义,以避免潜在的“严格模式下不允许八进制字面量”的错误。 - Dev

6

这是我为了有趣而编写的@Hristiyan Dodov答案的另一种不同版本。

regex = /^(a|e|i|o|u).*\1$/

const strings = ['abcde', 'abcda', 'aabcdaa', 'aeqwae', 'ouqweru']

strings.forEach((e)=>{
  const result = regex.test(e)
  console.log(e, result)
})


6

上面已经提到了正确的答案,这里只是为了更加明确:

regEx= /^([a,e,i,o,u])(.*)\1$/

在这里,\1 是反向引用,可以重复使用同一个反向引用来匹配相同的文本。大多数正则表达式支持最多99个捕获组和双位数反向引用。因此,如果你的正则表达式有99个捕获组,\99就是一个有效的反向引用。点击了解详情


1
/^([aeiou])[a-z]\1$/

稍作改进,以捕捉字母。


1
你的正则表达式 [a-z] 必须匹配并且只能匹配一次字母,例如 "aa" 和 "axxa" 将不会被匹配。但是你给了一个好建议,我使用 /^([aeiou])[a-z]*\1$/ 来替代。 - Jun Yu
要仅匹配一个,您可以像这样添加{1}: /^([aeiou]{1})[a-z]+\1$/ - Jacksonkr

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