Das war eine Interviewfrage, die ich nicht beantworten konnte:
Wie kann ich mithilfe regulärer Ausdrücke überprüfen, ob eine Zeichenfolge ein Palindrom ist?
ps Es gibt bereits eine Frage " Wie kann man überprüfen, ob die angegebene Zeichenfolge palindrom ist? ", und es gibt viele Antworten in verschiedenen Sprachen, aber keine Antwort, die reguläre Ausdrücke verwendet.
regex
palindrome
Degvik
quelle
quelle
Antworten:
Die Antwort auf diese Frage lautet: "Es ist unmöglich". Insbesondere fragt sich der Interviewer, ob Sie in Ihrem Unterricht in Computertheorie aufgepasst haben.
In Ihrem rechentheoretischen Kurs haben Sie etwas über endliche Zustandsmaschinen gelernt. Eine endliche Zustandsmaschine besteht aus Knoten und Kanten. Jede Kante ist mit einem Buchstaben aus einem endlichen Alphabet versehen. Ein oder mehrere Knoten sind spezielle "akzeptierende" Knoten und ein Knoten ist der "Start" -Knoten. Wenn jeder Buchstabe aus einem bestimmten Wort gelesen wird, durchlaufen wir die angegebene Kante in der Maschine. Wenn wir in einem akzeptierenden Zustand enden, sagen wir, dass die Maschine dieses Wort "akzeptiert".
Ein regulärer Ausdruck kann immer in eine äquivalente endliche Zustandsmaschine übersetzt werden. Das heißt, eines, das dieselben Wörter wie der reguläre Ausdruck akzeptiert und ablehnt (in der realen Welt erlauben einige reguläre Ausdruckssprachen beliebige Funktionen, diese zählen nicht).
Es ist unmöglich, eine endliche Zustandsmaschine zu bauen, die alle Palindrome akzeptiert. Der Beweis beruht auf den Tatsachen, dass wir leicht eine Zeichenfolge erstellen können, die eine beliebig große Anzahl von Knoten erfordert, nämlich die Zeichenfolge
a ^ xba ^ x (z. B. aba, aabaa, aaabaaa, aaaabaaaa, ....)
wobei a ^ x x-mal wiederholt wird. Dies erfordert mindestens x Knoten, da wir nach dem Erkennen des 'b' x-mal zurückzählen müssen, um sicherzustellen, dass es sich um ein Palindrom handelt.
Wenn Sie schließlich zur ursprünglichen Frage zurückkehren, können Sie dem Interviewer mitteilen, dass Sie einen regulären Ausdruck schreiben können, der alle Palindrome akzeptiert, die kleiner als eine endliche feste Länge sind. Wenn es jemals eine reale Anwendung gibt, bei der Palindrome identifiziert werden müssen, enthält sie mit ziemlicher Sicherheit keine willkürlich langen Anwendungen. Diese Antwort würde also zeigen, dass Sie theoretische Unmöglichkeiten von realen Anwendungen unterscheiden können. Trotzdem wäre der tatsächliche reguläre Ausdruck ziemlich lang, viel länger als ein gleichwertiges 4-Zeilen-Programm (einfache Übung für den Leser: Schreiben Sie ein Programm, das Palindrome identifiziert).
quelle
>=1.9
) hierWährend die PCRE- Engine rekursive reguläre Ausdrücke unterstützt (siehe die Antwort von Peter Krauss ), können Sie auf der ICU- Engine (wie sie beispielsweise von Apple verwendet wird) keinen regulären Ausdruck verwenden, um dies ohne zusätzlichen Code zu erreichen. Sie müssen so etwas tun:
Dies erkennt jedes Palindrom, erfordert jedoch eine Schleife (die erforderlich ist, da reguläre Ausdrücke nicht zählen können).
quelle
Es ist nicht möglich. Palindrome werden nicht durch eine reguläre Sprache definiert. (Siehe, ich habe etwas in der Computertheorie gelernt)
quelle
Mit Perl Regex:
Wie viele betont haben, kann dies jedoch nicht als regulärer Ausdruck angesehen werden, wenn Sie streng sein möchten. Reguläre Ausdrücke unterstützen keine Rekursion.
quelle
/u
Modifikator hinzufügen ), oder an Kombinatorzeichen. (durch.
die\X
Escape-Sequenz ersetzen ).abababa
. Bei Verwendung von PCRE-basierten Regex-Engines ist es nicht möglich, die Rekursion für jede Eingabe zu aktivieren. Casimirs Regex verwendet einen anderen Ansatz, der Iteration und veränderlichen Zustand verwendet, und ist ziemlich faszinierend.Hier ist eine, um 4-Buchstaben-Palindrome (z. B. Tat) für jede Art von Zeichen zu erkennen:
Hier ist eine, um Palindrome mit 5 Buchstaben (z. B. Radar) zu erkennen und nur nach Buchstaben zu suchen:
Es scheint also, dass wir für jede mögliche Wortlänge einen anderen regulären Ausdruck benötigen. Dieser Beitrag auf einer Python-Mailingliste enthält einige Details zum Grund (Finite State Automata und Pumping Lemma).
quelle
Je nachdem, wie sicher Sie sind, würde ich folgende Antwort geben:
quelle
Ja , Sie können es in .Net tun!
Sie können es hier überprüfen ! Es ist ein wunderbarer Beitrag!
quelle
StackOverflow ist voll von Antworten wie "Reguläre Ausdrücke? Nein, sie unterstützen es nicht. Sie können es nicht unterstützen."
Die Wahrheit ist, dass reguläre Ausdrücke nichts mehr mit regulären Grammatiken zu tun haben . Moderne reguläre Ausdrücke verfügen über Funktionen wie Rekursions- und Ausgleichsgruppen, und die Verfügbarkeit ihrer Implementierungen nimmt ständig zu (siehe hier beispielsweise Ruby-Beispiele). Meiner Meinung nach ist es nur kontraproduktiv, an der alten Überzeugung festzuhalten, dass reguläre Ausdrücke in unserem Bereich alles andere als ein Programmierkonzept sind. Anstatt sie für die Wortwahl zu hassen, die nicht mehr am besten geeignet ist, ist es Zeit für uns, Dinge zu akzeptieren und weiterzumachen.
Hier ist ein Zitat von Larry Wall , dem Schöpfer von Perl selbst:
Und hier ist ein Blog-Beitrag von einem der Hauptentwickler von PHP :
Davon abgesehen können Sie Palindrome mit regulären Ausdrücken abgleichen:
... was offensichtlich nichts mit regulären Grammatiken zu tun hat.
Weitere Informationen hier: http://www.regular-expressions.info/balancing.html
quelle
Wie einige bereits gesagt haben, gibt es keinen einzigen regulären Ausdruck, der ein allgemeines Palindrom sofort erkennt. Wenn Sie jedoch Palindrome bis zu einer bestimmten Länge erkennen möchten, können Sie so etwas wie verwenden
quelle
Dies kann jetzt in Perl erfolgen. Rekursive Referenz verwenden:
geändert basierend auf dem letzten Teil http://perldoc.perl.org/perlretut.html
quelle
In Ruby können Sie benannte Erfassungsgruppen verwenden. so etwas wird funktionieren -
Probieren Sie es aus, es funktioniert ...
quelle
Es ist tatsächlich einfacher, dies mit der Manipulation von Zeichenfolgen zu tun, als mit regulären Ausdrücken:
Mir ist klar, dass dies die Interviewfrage nicht wirklich beantwortet, aber Sie könnten damit zeigen, wie Sie eine Aufgabe besser erledigen können, und Sie sind nicht die typische Person mit einem Hammer, die jedes Problem als Nagel ansieht . "
quelle
Hier ist meine Antwort auf Regex Golfs 5. Level (Ein Mann, ein Plan). Es funktioniert mit Regexp des Browsers für bis zu 7 Zeichen (ich verwende Chrome 36.0.1985.143).
Hier ist eine für bis zu 9 Zeichen
Um die maximale Anzahl von Zeichen zu erhöhen, für die es funktionieren würde, würden Sie wiederholt ersetzen . mit (?: (.).? \ n?)? .
quelle
Rekursive reguläre Ausdrücke können es tun!
So einfacher und selbstverständlicher Algorithmus, um eine Zeichenfolge zu erkennen, die ein Palindrom enthält:
Unter rexegg.com/regex-recursion erklärt das Tutorial, wie es funktioniert.
Es funktioniert gut mit jeder Sprache, hier ein Beispiel aus derselben Quelle (Link) wie Proof-of-Concept mit PHP:
Ausgänge
Vergleichen
Der reguläre Ausdruck
^((\w)(?:(?1)|\w?)\2)$
erledigt den gleichen Job, aber als yes / not "enthält".PS: Es wird eine Definition verwendet, bei der "o" kein Palimrom ist, das Bindestrich-Format "able-elba" kein Palindrom ist, "ableelba" jedoch. Benennung es definition1 .
Wenn "o" und "able-elba" Palindronen sind, benennen Sie definition2 .
Vergleich mit anderen "Palindrom-Regexen",
^((.)(?:(?1)|.?)\2)$
die Basis-Regex oben ohne\w
Einschränkung, akzeptiert "able-elba".^((.)(?1)?\2|.)$
( @LilDevil ) Verwenden Sie definition2 (akzeptiert "o" und "able-elba", die sich auch in der Erkennung von "aaaaa" - und "bbbb" -Strings unterscheiden).^((.)(?1)\2|.?)$
( @Markus ) weder "kook" noch "bbbb" erkannt^((.)(?1)*\2|.?)$
( @Csaba ) Verwenden Sie definition2 .HINWEIS: Zum Vergleichen können Sie
$subjects
für jeden verglichenen regulären Ausdruck mehr Wörter und eine Zeile hinzufügen.quelle
Sie können dies auch ohne Rekursion tun:
um ein einzelnes Zeichen zuzulassen:
Funktioniert mit Perl, PCRE
Demo
Für Java:
Demo
quelle
In Bezug auf den PCRE-Ausdruck (von MizardX):
/^((.)(?1)\2|.?)$/
Hast du es getestet? Auf meinem PHP 5.3 unter Win XP Pro schlägt dies fehl: aaaba Eigentlich habe ich den Ausdruck Ausdruck leicht geändert, um zu lesen:
/^((.)(?1)*\2|.?)$/
Ich denke, was passiert ist, dass das äußere Zeichenpaar zwar verankert ist, die übrigen jedoch nicht. Dies ist nicht ganz die ganze Antwort, denn während "aaaba" und "aabaacaa" fälschlicherweise weitergegeben werden, schlägt es bei "aabaaca" korrekt fehl.
Ich frage mich, ob es eine Lösung dafür gibt und ob das Perl-Beispiel (von JF Sebastian / Zsolt) meine Tests korrekt besteht.
Csaba Gabor aus Wien
quelle
Es gilt für die Oniguruma-Engine (die in Ruby verwendet wird).
aus dem Pragmatischen Bücherregal genommen
quelle
In Perl (siehe auch Zsolt Botykais Antwort ):
quelle
Wie von ZCHudson hervorgehoben , kann festgestellt werden, ob etwas ein Palindrom ist, das nicht mit einem üblichen regulären Ausdruck ausgeführt werden kann, da der Palindromsatz keine reguläre Sprache ist.
Ich bin völlig anderer Meinung als Airsource Ltd, wenn er sagt, dass "es nicht möglich ist" nicht die Art von Antwort ist, nach der der Interviewer sucht. Während meines Interviews komme ich zu dieser Art von Frage, wenn ich einem guten Kandidaten gegenüberstehe, um zu prüfen, ob er das richtige Argument finden kann, als wir ihm vorgeschlagen haben, etwas falsch zu machen. Ich möchte niemanden einstellen, der versucht, etwas falsch zu machen, wenn er es besser kennt.
quelle
etwas, das Sie mit Perl tun können: http://www.perlmonks.org/?node_id=577368
quelle
Ich würde dem Interviewer erklären, dass die aus Palindromen bestehende Sprache keine reguläre Sprache ist, sondern kontextfrei.
Der reguläre Ausdruck, der zu allen Palindromen passen würde, wäre unendlich . Stattdessen würde ich vorschlagen, dass er sich entweder auf eine maximale Größe von Palindromen beschränkt, um sie zu akzeptieren; oder wenn alle Palindrome benötigt werden, verwenden Sie mindestens eine Art von NDPA oder verwenden Sie einfach die einfache String-Umkehr- / Gleichheitstechnik.
quelle
Das Beste, was Sie mit regulären Ausdrücken tun können, bevor Ihnen die Erfassungsgruppen ausgehen:
Dies entspricht allen Palindromen mit einer Länge von bis zu 19 Zeichen.
Das programmgesteuerte Lösen für alle Längen ist trivial:
quelle
Ich habe noch nicht den Repräsentanten, um Inline-Kommentare abzugeben, aber der von MizardX bereitgestellte und von Csaba geänderte Regex kann weiter geändert werden, damit er in PCRE funktioniert. Der einzige Fehler, den ich gefunden habe, ist die Zeichenfolge mit einem Zeichen, aber ich kann das separat testen.
/^((.)(?1)?\2|.)$/
Wenn Sie es bei anderen Zeichenfolgen zum Scheitern bringen können, kommentieren Sie dies bitte.
quelle
quelle
Aus der Automatentheorie ist es unmöglich, ein Paliandrom beliebiger Länge zu finden (da dies unendlich viel Speicher erfordert). Es ist jedoch möglich, Paliandrome mit fester Länge anzupassen. Angenommen, es ist möglich, einen regulären Ausdruck zu schreiben, der allen Paliandromen der Länge <= 5 oder <= 6 usw. entspricht, jedoch nicht> = 5 usw., wenn die Obergrenze unklar ist
quelle
In Ruby können Sie
\b(?'word'(?'letter'[a-z])\g'word'\k'letter+0'|[a-z])\b
palindrome Wörter wie za, dad, radar, racecar, and redivider
. ps: Dieser reguläre Ausdruck stimmt nur mit palindromen Wörtern überein, die eine ungerade Anzahl von Buchstaben lang sind.Mal sehen, wie dieser Regex zum Radar passt. Die Wortgrenze \ b stimmt am Anfang der Zeichenfolge überein. Die Regex-Engine gibt die Erfassungsgruppe "Wort" ein. [az] stimmt mit r überein, das dann im Stapel für die Erfassungsgruppe "Buchstabe" auf der Rekursionsstufe Null gespeichert wird. Jetzt gibt die Regex-Engine die erste Rekursion der Gruppe "Wort" ein. (? 'letter' [az]) stimmt mit einem auf Rekursionsstufe 1 überein und erfasst es. Der Regex gibt die zweite Rekursion der Gruppe "Wort" ein. (? 'Buchstabe' [az]) erfasst d auf Rekursionsstufe zwei. Während der nächsten zwei Rekursionen erfasst die Gruppe a und r auf den Ebenen drei und vier. Die fünfte Rekursion schlägt fehl, da in der Zeichenfolge keine Zeichen mehr vorhanden sind, damit [az] übereinstimmt. Die Regex-Engine muss zurückverfolgen.
Die Regex-Engine muss nun die zweite Alternative innerhalb der Gruppe "Wort" ausprobieren. Das zweite [az] in der Regex entspricht dem letzten r in der Zeichenfolge. Die Engine verlässt nun eine erfolgreiche Rekursion und geht eine Ebene zurück bis zur dritten Rekursion.
Nach dem Abgleich (& Wort) erreicht die Engine \ k'letter + 0 '. Die Rückreferenz schlägt fehl, weil die Regex-Engine bereits das Ende der Betreffzeichenfolge erreicht hat. Also zieht es sich wieder zurück. Die zweite Alternative entspricht jetzt der a. Die Regex-Engine verlässt die dritte Rekursion.
Die Regex-Engine hat erneut eine Übereinstimmung (& word) und muss die Rückreferenz erneut versuchen. Die Rückreferenz gibt +0 oder die aktuelle Rekursionsstufe an, die 2 ist. Auf dieser Stufe stimmte die Erfassungsgruppe mit d überein. Die Rückreferenz schlägt fehl, weil das nächste Zeichen in der Zeichenfolge r ist. Beim zweiten Zurückverfolgen entspricht die zweite Alternative d.
Jetzt stimmt \ k'letter + 0 'mit dem zweiten a in der Zeichenfolge überein. Dies liegt daran, dass die Regex-Engine bei der ersten Rekursion angekommen ist, bei der die Erfassungsgruppe mit der ersten a übereinstimmte. Die Regex-Engine verlässt die erste Rekursion.
Die Regex-Engine ist jetzt wieder außerhalb aller Rekursionen. Dass diese Ebene die Erfassungsgruppe r gespeichert. Die Rückreferenz kann jetzt mit dem letzten r in der Zeichenfolge übereinstimmen. Da sich die Engine nicht mehr in einer Rekursion befindet, wird der Rest des regulären Ausdrucks nach der Gruppe fortgesetzt. \ b stimmt mit dem Ende der Zeichenfolge überein. Das Ende der Regex ist erreicht und das Radar wird als Gesamtspiel zurückgegeben.
quelle
Hier ist PL / SQL-Code, der anhand regulärer Ausdrücke angibt, ob eine bestimmte Zeichenfolge palindrom ist oder nicht:
quelle
quelle
Diese Regex erkennt Palindrome mit bis zu 22 Zeichen, wobei Leerzeichen, Tabulatoren, Kommas und Anführungszeichen ignoriert werden.
Spielen Sie hier damit: https://regexr.com/4tmui
quelle
Eine leichte Verfeinerung der Methode von Airsource Ltd im Pseudocode:
quelle