Wie erkennt dieses PCRE-Muster Palindrome?

Diese Frage ist eine didaktische Demonstration der Verwendung von Lookahead, verschachtelten Verweisen und Bedingungen in einem PCRE-Muster, um ALLE Palindrome abzugleichen, einschließlich derer, die nicht mit dem in der PCRE-Manpage angegebenen rekursiven Muster übereinstimmen.

Prüfen Sie dieses PCRE-Muster im PHP-Snippet:

$palindrome = '/(?x)
^
  (?:
      (.) (?=
              .*
              (
                \1
                (?(2) \2 | )
              )
              $
          )
  )*
  .?
  \2?
$


/';

Dieses Muster scheint Palindrome zu erkennen, wie in diesen Testfällen siehe auch auf ideone.com):

$tests = array(
  # palindromes
  '',
  'a',
  'aa',
  'aaa',
  'aba',
  'aaaa',
  'abba',
  'aaaaa',
  'abcba',
  'ababa',

  # non-palindromes
  'aab',
  'abab',
  'xyz',
);

foreach ($tests as $test) {
  echo sprintf("%s '%s'\n", preg_match($palindrome, $test), $test);  
}

Wie funktioniert dieses Muster?

Anmerkunge

Dieses Muster verwendet einnested reference, eine ähnliche Technik wieWie erkennt dieser Java-Regex Palindrome?, aber im Gegensatz zu diesem Java-Muster gibt es kein Lookbehind (aber es verwendet einbeding).

eachten Sie auch, dass der PCREman page präsentiert ein rekursives Muster, das mit einigen Palindromen übereinstimmt:

# the recursive pattern to detect some palindromes from PCRE man page
^(?:((.)(?1)\2|)|((.)(?3)\4|.))$

Die Manpage warnt, dass dieses rekursive Muster NICHT alle Palindrome erkennen kann (siehe:Warum stimmt diese rekursive Regex nur dann überein, wenn ein Charakter 2 @ wiederhon - 1 mal undauch auf ideone.com), aber das in dieser Frage dargestellte verschachtelte Referenz- / Positiv-Lookahead-Muster kann.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage