将Perl正则表达式翻译为.NET

20

我在Perl中有一些有用的正则表达式。有没有简单的方法将它们翻译成.NET的正则表达式方言?

如果没有,是否有简明的差异参考资料?

3个回答

38

http://www.regular-expressions.info/refflavors.html 中有一个很大的比较表格。


大多数基本元素都是相同的,不同之处在于:

次要差异:

  • Unicode 转义序列。在 .NET 中为 \u200A,在 Perl 中为 \x{200A}
  • .NET 中的 \v 仅表示垂直制表符(U+000B),而在 Perl 中它代表 "垂直空白" 类别。当然,在 Perl 中有 \V
  • 在 .NET 中,命名引用的条件表达式为 (?(name)yes|no),但在 Perl 中为 (?(<name>)yes|no)

一些元素仅存在于 Perl 中:

  • 占有量词(x?+x*+x++ 等等)。使用非回溯子表达式((?>…))代替。
  • 命名 Unicode 转义序列 \N{LATIN SMALL LETTER X}\N{U+200A}
  • 大小写转换和转义
    • \l(下一个字符转换为小写)、\u(下一个字符转换为大写)。
    • \L(全部转换为小写)、\U(全部转换为大写)、\Q(引用元字符直到 \E)。
  • Unicode 属性的简写符号 \pL\PL。在 .NET 中必须包含花括号,例如:\p{L}
  • 一些奇怪的东西,如 \X\C
  • 特殊字符类,例如\v\V\h\H\N\R
  • 对特定或先前组的反向引用\g1\g{-1}。在.NET中只能使用绝对组索引。
  • 命名反向引用\g{name}。请改用\k<name>
  • POSIX字符类[[:alpha:]]
  • 分支重置模式(?|…)
  • \K。请改用正向先行断言((?<=…))。
  • 代码评估断言(?{…}),延迟子表达式(??{…})
  • 子表达式引用(递归模式)(?0)(?R)(?1)(?-1)(?+1)(?&name)
  • 某些条件表达式的谓词是Perl特有的:
    • 代码(?{…})
    • 递归(R)(R1)(R&name)
    • 定义(DEFINE)
  • 特殊回溯控制动词(*VERB:ARG)
  • Python语法
    • (?P<name>…)。请改用(?<name>…)
    • (?P=name)。请改用\k<name>
    • (?P>name)。在.NET中没有相应的语法。
  • 一些元素只适用于.NET:

    • 变长后顾引用。在 Perl 中,对于正向后顾引用,请使用\K
    • 条件表达式中可以使用任意正则表达式 (?(pattern)yes|no)
    • 字符类减法(未记录?) [a-z-[d-w]]
    • 平衡组 (?<-name>…)。这可以通过代码评估断言(?{…})后跟一个(?&name)来模拟实现。

    参考资料:


    2
    太棒了,谢谢...顺便说一句,我很惊喜两种方言是多么兼容,甚至包括look-around等。我之前也不知道.NET中的Regex.Replace方法支持替换匹配的带括号子表达式($1、$2等),像这样:str = Regex.Replace(str, @"([a-z]+):(\d+)", m => m.Result("$1 -- $2")) 这对应于Perl中的:s/([a-z]+):(\d+)/$1 -- $2/g - JoelFan
    一些元素只支持Perl语言,但并没有提到字符转换(例如tr/tgca/acgt/),所以应该是支持的,不是吗? - mbx
    @mbx:我认为字符翻译不属于正则表达式的一部分。 - kennytm
    1
    很好的回答。我想补充一下:当你在单个正则表达式中混合使用命名和未命名捕获组时,它们被引用的顺序是不同的。在Perl中,perl -E "@captures = 'word1 word2 word3' =~ /(?<name1>\w+)\s+(\w+)\s+(\w+)/; foreach my $c (@captures){say $c}"仍然输出为word1 word2 word3,而在.NET正则表达式中,它将输出为word2 word3 word1,因为未命名组在正则表达式引擎按顺序排列捕获组时具有优先级。这可能会对从一种语言翻译成另一种语言的复杂正则表达式产生影响。 - knb

    4

    它们被 设计成与 Perl 5 正则表达式兼容。因此,Perl 5 正则表达式 应该 在 .NET 中正常工作。

    您可以将一些RegexOptions翻译如下:

    [Flags]
    public enum RegexOptions
    {
      Compiled = 8,
      CultureInvariant = 0x200,
      ECMAScript = 0x100,
      ExplicitCapture = 4,
      IgnoreCase = 1,                 // i in Perl
      IgnorePatternWhitespace = 0x20, // x in Perl
      Multiline = 2,                  // m in Perl
      None = 0,
      RightToLeft = 0x40,
      Singleline = 0x10               // s in Perl
    }
    

    另一个提示是使用原始字符串,这样您就不需要在C#中转义所有这些转义字符:

    string badOnTheEyesRx    = "\\d{4}/\\d{2}/\\d{2}";
    string easierOnTheEyesRx = @"\d{4}/\d{2}/\d{2}";
    

    3
    @Eric:两者都不是彼此的超集。 - kennytm
    2
    不,.NET是在Perl 5之后出现的,并复制了它成功的正则表达式语法。 - Jordão
    1
    @KennyTM => .NET 有哪些 Perl 没有的功能?Perl 具有嵌入式代码执行 (?{ code })(??{ code }),能够递归到捕获组... - Eric Strom
    1
    @Eric: 平衡组 - kennytm
    1
    @Eric:(1)那是作弊;(2)我没有说.NET是Perl的超集,我说它们属于不同的集合(插入Venn图)。 - kennytm
    显示剩余2条评论

    1

    这真的取决于正则表达式的复杂性 - 许多正则表达式可以直接使用相同的方式工作。

    查看this .NET 正则表达式速查表,以查看运算符是否按照您的预期进行操作。

    我不知道是否有任何工具可以自动翻译正则表达式方言之间的差异。


    RegexBuddy可以接受各种风格的正则表达式,并将其转换为其他风格——只要目标风格支持所需的功能。 - Tim Pietzcker

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接