Wie kehrt diese Regex-Ersetzung eine Zeichenfolge um?

Dies ist der vierte Teil einer Reihe von Artikeln zu Bildungsfragen. Es zeigt, wie die Kombination aus verschachtelter Referenz (siehe:Wie findet dieser Regex Dreieckszahlen?) zum "Zählen" innerhalb von Behauptungen (siehe:Wie können wir a ^ n b ^ n mit Java Regex abgleichen?) kann verwendet werden, um eine Zeichenfolge umzukehren. Das programmgesteuert generierte Muster verwendet Metamusterabstraktionen (siehe:Wie erkennt dieser Java-Regex Palindrome?). Zum ersten Mal in der Serie werden diese Techniken zum Ersetzen anstelle der vollständigen Zeichenfolgenübereinstimmung verwendet.

Vollständig funktionierende Java- und C # -Implementierungen werden bereitgestellt. Inspirierende Zitate enthalten.

Das Umkehren eines Strings mit regulären Ausdrücken schien nie eine gute Idee zu sein, und es war auch nicht sofort ersichtlich, ob dies überhaupt möglich war, und wenn ja, wie man es versuchen könnte.

Während es @ iimmer noc keine gute Idee, zumindest wissen wir jetzt, dass es möglich ist, denn hier ist eine Möglichkeit, es zu tun:

C #(auch auf ideone.com)
using System;
using System.Text.RegularExpressions;

public class TwoDollarReversal {    
public static void Main() {
   string REVERSE = 
      @"(?sx) . grab$2"
         .Replace("grab$2",
            ForEachDotBehind(
               AssertSuffix(@"((.) \1?)")
            )
         );
   Console.WriteLine(
      Regex.Replace(
         @"nietsniE treblA --
         hguone llew ti dnatsrednu t'nod uoy ,ylpmis ti nialpxe t'nac uoy fI",

         REVERSE, "$2"
      )
   );
   // If you can't explain it simply, you don't understand it well enough
   // -- Albert Einstein
}      
// performs an assertion for each dot behind current position
static string ForEachDotBehind(string assertion) {
   return "(?<=(?:.assertion)*)".Replace("assertion", assertion);
}
// asserts that the suffix of the string matches a given pattern
static string AssertSuffix(string pattern) {
   return "(?=.*$(?<=pattern))".Replace("pattern", pattern);
}

}
Java(auch auf ideone.com)
class TwoDollarReversal {

public static void main(String[] args) {
   String REVERSE =
      "(?sx) . grab$2"
         .replace("grab$2",
            forEachDotBehind(
               assertSuffix("((.) \\1?)")
            )
         );

   System.out.println(
      "taerG eht rednaxelA --\nyrt lliw ohw mih ot elbissopmi gnihton si erehT"
         .replaceAll(REVERSE, "$2")
   );
   // There is nothing impossible to him who will try
   // -- Alexander the Great"
}

static String forEachDotBehind(String assertion) {
   return "(?<=^(?:.assertion)*?)".replace("assertion", assertion);
}
static String assertSuffix(String pattern) {
   return "(?<=(?=^.*?pattern$).*)".replace("pattern", pattern);
}

}

Beide C # - und Java-Versionen scheinen denselben Gesamtalgorithmus zu verwenden, mit geringfügigen Abweichungen nur in den abstrakten Implementierungsdetails.

ies ist offensichtlich nicht die beste, einfachste und effizienteste Möglichkeit, eine Zeichenfolge umzukehre. Das heißt, im Interesse des Lernens über Regex; wie man Muster konzeptualisiert; wie der Motor funktioniert, um sie zusammenzubringen; wie man verschiedene Teile zusammensetzt, um das zu bauen, was wir wollen; wie dies lesbar und wartbar gemacht wird; und nur aus freude daran, etwas neues zu lernen, können wir erklären, wie das funktioniert?

Anhang: Spickzettel!

Dies ist eine kurze Beschreibung der verwendeten Regex-Grundkonstrukte:

(?sx) ist das eingebettete Flag Modifikatoren. s aktiviert den "einzeiligen" Modus, wodurch dasPunk passenIRGENDEI Zeichen einschließlic newlines).x aktiviert das Freiraum -Modus, in dem nicht maskierte Leerzeichen ignoriert werden (und# kann für Kommentare verwendet werden.^ und$ sind der Anfang und das Ende der Zeile Anker.? als Wiederholungsangabe bezeichnetOptiona (d. h. Null oder Eins von). Als Wiederholungsquantifizierer in z..*? es zeigt an, dass das* (d. h. null oder mehr) Wiederholungen sind nur ungern/nicht geizig(…) werden für @ verwendGruppierun. (?:…) ist eine nicht erfassende Gruppe. Eine Erfassungsgruppe speichert die Zeichenfolge, mit der sie übereinstimmt. es erlaubt rückwärts / vorwärts / verschachtelte Referenzen (z. B.\1), Ersatzsubstitution (z. B.$2), etc(?=…) ist ein positivesSchau vorau; es sieht nach rechts aus, um zu behaupten, dass es eine Übereinstimmung des gegebenen Musters gibt.(?<=…) ist ein positivesschaue zurüc; es sieht nach links aus.Sprachenreferenzen / zusätzliche RessourcenMSDN - Sprachelemente für reguläre Ausdrücke -System.Text.RegularExpressionsJava Tutorials / Grundlegende Klassen / Reguläre Ausdrücke -java.util.regex.Pattern

Antworten auf die Frage(2)

Ihre Antwort auf die Frage