使用正则表达式查找回文字符串

10

这个问题是为了理解一个回答而提出的:如何使用正则表达式检查字符串是否为回文?

Markus Jarderot 给出的答案是:

/^((.)(?1)\2|.?)$/

有人能解释一下,这里到底发生了什么...我需要在Perl中做类似的事情,但是无法理解这个解决方案!!!

附注:我不太擅长Perl,所以请轻一点...还有,“如果你想严格一点,这不能被认为是正则表达式”——我看到了这句话,所以我知道这不是严格的正则表达式


9
“我需要在 Perl 中做类似的事情”,这是针对 Perl 的请求。 - ikegami
1
Perl正则表达式语法在perlre中有详细描述。 - ikegami
3
顺便提一下,您不必使用正则表达式来检查字符串是否为回文。简单情况下只需一个代码行即可轻松实现: sub is_palindromic { $_[0] eq reverse $_[0] } - Zaid
2
@NoobEditor,这不是对拼写的评论。我的意思是发布的代码是Perl代码,所以请求Perl代码有点奇怪。(perl可执行文件或Perl语言都有意义。) - ikegami
显示剩余4条评论
3个回答

14
  • ^ - 匹配字符串的开头
  • ( - 开始捕获组 #1
  • (.) - 匹配除换行符以外的任何单个字符,并将其保存在捕获组 #2 中
  • (?1) - 递归 = 将此组替换为整个正则表达式捕获组 #1
  • \2 - 匹配与捕获组 #2 相同的内容。这要求字符串的第一个和最后一个字符相匹配。
  • | - 创建一个可选项
  • .? - 可选地匹配除换行符以外的任何一个字符 - 这用于处理递归的结尾,通过匹配空字符串(当整个字符串长度为偶数时)或单个字符(当它是奇数长度时)来结束递归。
  • ) - 结束捕获组 #1
  • $ - 匹配字符串的结尾或字符串末尾的换行符。

关键在于递归部分(?1)。回文是一个空字符串、一个单字符字符串或一个首尾字符相同并且它们之间的子字符串也是回文的字符串。


一个由1个字符组成的字符串,其第一个和最后一个字符相同。 - Barmar
递归(?1)是让我困惑的地方!!:\ - NoobEditor
1
@NoobEditor,它在标题“(?PARNO) (?-PARNO) (?+PARNO) (?R) (?0)”下有记录。 - ikegami
那偶数长度的回文呢? - Atav32
@Atav32请阅读第7个项目,它解释了偶数和奇数的情况。 - Barmar

3

这个类比函数可能更容易理解,它用于处理数组的同样操作:

sub palindrome {
  if (scalar(@_) >= 2) {
    my $first_dot = shift;
    my $slash_two = pop;
    return $first_dot eq $slash_two && palindrome(@_);
  } else {
    # zero or one items
    return 1;
  }
}

print "yes!\n" if palindrome(qw(one two three two one));
print "really?\n" if palindrome(qw(one two three two two one));
(?1)表示正则表达式中第一个括号起始位置的递归引用,\2是当前递归中对(.)的反向引用。这两个符号锚定在“当前递归深度匹配的内容”的开头和结尾,所以其他所有东西都在下一个深度匹配。ikegami认为这会更快。
sub palindrome {
   my $next = 0;
   my %symbols;
   my $s = join '', map chr( $symbols{$_} ||= $next++ ), @_;
   return $s =~ /^((.)(?1)\2|.?)\z/s;
}

@ikegami,这个答案的重点不是速度,而是为那些不理解最后一行的人提供清晰明了的解释。 - bazzargh

0
我几天前写了这个正则表达式。 如果你像这样使用它,它会给你一个包含某个文本中所有回文的数组。 这个例子是针对#JavaScript的,但你可以在任何语言中使用正则表达式来完成工作。 适用于长度为21个字符或数字的单词。如果需要,您可以使其更精确。
const palindromeFinder = /\b(\w?)(\w?)(\w?)(\w?)(\w?)(\w?)(\w?)(\w?)(\w?)(\w)\S?\10\9\8\7\6\5\4\3\2\1\b/g;

console.log(inputString.match(palindromeFinder));

1
这样匹配任何不是回文的东西真的很低效,因为正则表达式引擎会尝试每个\w?的匹配/非匹配字符的所有组合。这还不包括它由于21个字符限制而受到的有限用处。 - Abigail

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