这个正则表达式替换如何反转字符串?

时间:2010-09-12 04:06:52

标签: c# java regex lookaround nested-reference

  

这是一系列教育正则表达式文章的第四部分。它显示了如何在断言中使用嵌套引用(请参阅:How does this regex find triangular numbers?)与“count”的组合(请参阅:How can we match a^n b^n with Java regex?)来反转字符串。以编程方式生成的模式使用元模式抽象(请参阅:How does this Java regex detect palindromes?)。该系列中首次使用这些技术代替整个字符串匹配。

     

提供了完整的Java和C#实现。鼓舞人心的报价包括在内。

使用正则表达式反转字符串似乎不是一个好主意,如果可能的话,它甚至不会立即变得明显,如果是这样,那么人们可能会尝试这样做。

虽然不是一个好主意,但至少现在我们知道这是可能的,因为这是一种方法:

C# also on 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 also on 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)是嵌入式标志 modifiers s启用“单线”模式,允许 dot 匹配 ANY 字符(包括换行符) 。 x启用free-spacing模式,其中忽略未转义的空格(并且#可用于评论)。
  • ^$ anchors 的开头和结尾。
  • ?作为重复说明符表示optional(即零或一)。作为例如重复量化器。 .*?它表示*(即零或多个)重复是 reluctant /非贪婪。
  • (…)用于 grouping (?:…)是一个非捕获组。捕获组保存匹配的字符串;它允许后退/前进/嵌套引用(例如\1),替换替换(例如$2)等。
  • (?=…)是一个积极的 lookahead ;它看起来有权断言给定模式的匹配。 (?<=…)是一个积极的 lookbehind ;它向左看。

语言参考/其他资源

1 个答案:

答案 0 :(得分:7)