Как эта замена регулярного выражения меняет направление строки?

Это четвертая часть в серии учебных статей о регулярных выражениях. как комбинация вложенных ссылок (см .: Как это регулярное выражение находит треугольные числа? ) для «подсчета» в утверждениях (см .: Как мы можем сопоставить ^ nb ^ n с регулярным выражением Java? ) может использоваться для переворота строки. Программно сгенерированный шаблон использует абстракции мета-шаблона (см .: Как это регулярное выражение Java обнаруживает палиндромы? ). Впервые в серии эти методы используются для замены вместо сопоставления всей строки.

Предоставляются полные рабочие реализации Java и C #. Включены вдохновляющие цитаты.

Обращение строки с помощью регулярных выражений никогда не казалось хорошей идеей, и даже не сразу было очевидно, возможно ли это вообще, и если да, то как это можно было бы попытаться сделать.

Хотя это возможно. все еще не очень хорошая идея, по крайней мере, теперь мы знаем, что это возможно, потому что вот один способ сделать это:

C # ( также на 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 ( также на 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);
}

}

Похоже, что в версиях C # и Java используется один и тот же общий алгоритм с небольшими вариациями только в абстрактных деталях реализации.

Очевидно, это не самый лучший, самый простой, самый эффективный способ перевернуть строку . Тем не менее, в интересах изучения регулярного выражения; как концептуализировать паттерны; как двигатель работает, чтобы соответствовать им; как соединить различные части, чтобы построить то, что мы хотим; как сделать это в удобочитаемом и поддерживаемом виде; и просто ради удовольствия узнать что-то новое, можем ли мы объяснить, как это работает?


Приложение: шпаргалка!

Это краткое описание основных используемых конструкций регулярных выражений:

  • (? sx ) - это встроенные модификаторы флага . s включает "однострочный" режим, позволяя точке соответствовать ЛЮБОМУ символу ( включая символы новой строки). x включает режим свободного интервала , где неэкранированные пробелы игнорируются (и # может использоваться для комментариев).
  • ^ и $ - начало и конец строки якоря .
  • ? как спецификатор повторения обозначает необязательный (т. е. ноль или один из). В качестве количественного показателя повторения, например, в . *? он означает, что * (то есть ноль или более) повторение неохотно / не жадно.
  • (…) используются для группировки . (?:…) - это группа без захвата. Группа захвата сохраняет строку, которой соответствует; он допускает обратные / прямые / вложенные ссылки (например, \ 1 ), заменяющую подстановку (например, $ 2 ) и т. д.
  • (? =…) является положительным вперед ; он смотрит вправо, чтобы утверждать, что существует соответствие заданному шаблону. (? - положительный просмотр назад ; он смотрит налево.

Ссылки на языки / дополнительные ресурсы

16
задан Community 23 May 2017 в 12:33
поделиться