【问题标题】:Perl: regex for conditional replace?Perl:条件替换的正则表达式?
【发布时间】:2019-07-11 15:13:08
【问题描述】:

在这个字符串中

ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<

我想根据前面括号之间的字符将XY&lt; 之间的每个子字符串替换为一个或两个:

如果XY(CN) 之后用ONE 替换子字符串

如果XY(CI) 之后用TWO 替换子字符串

所以结果应该是:

ab<(CN)cdONE<(CI)efgTWO<(CN)zONE<(CI)efgTWO<

XY 和后面的字符应该被替换,但不能替换尖括号&lt;

这是为了修改 HTML,XY&lt; 之间可以出现任意字符。 我想我需要 (CN) 和 (CI) 的两个正则表达式。

# This one replaces just all XY:   
my $s = 'ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';
$s =~ s/(XY(.*?))</ONE/g;    
# But how to add the conditions to the regex?

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    这可以在一行正则表达式中使用/e/replace/ 中的三元运算符? 完成。 /r 选项返回结果字符串,实际上这将保持原始字符串 $s 不变。

    use strict;
    use warnings;
    
    my $s ='ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';
    print (($s=~s/\(([^)]+)\)([^(]+)XY[^(]+</"($1)$2".(($1 eq CN)?ONE:TWO)."<"/gre)."\n");
    

    输出:

    ab<(CN)cdONE<(CI)efgTWO<(CN)zONE<(CI)efgTWO<
    

    【讨论】:

      【解决方案2】:

      您不需要两个正则表达式。捕获C[NI] 并从哈希中检索相应的替换值:

      #!/usr/bin/perl
      use warnings;
      use strict;
      
      my $s = 'ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';
      
      my %replace = (CN => 'ONE', CI => 'TWO');
      
      $s =~ s/(\((C[NI])\).*?)XY.*?</$1$replace{$2}</g;
      
      my $exp = 'ab<(CN)cdONE<(CI)efgTWO<(CN)zONE<(CI)efgTWO<';
      
      use Test::More tests => 1;
      is $s, $exp;
      

      【讨论】:

      • 谢谢,这行得通。实际上我需要更多的括号之间的字符组合,所以我将 (C[NI]) 替换为 (CN|CO|IN)
      • @Fabian_Z071:如果您还在 %replace 哈希中添加了一个新对,那么一切都应该正常工作:-)
      【解决方案3】:

      我的猜测是这个表达式或者它的修改版本可能会起作用,但不确定:

      ([a-z]{2}<\([A-Z]{2}\)[a-z]{2})([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)(<\([A-Z]{2}\)[a-z])([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)<
      

      测试

      use strict;
      use warnings;
      
      my $str = 'ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';
      my $regex = qr/([a-z]{2}<\([A-Z]{2}\)[a-z]{2})([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)(<\([A-Z]{2}\)[a-z])([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)</mp;
      my $subst = '"$1ONE$3TWO$5ONE$7TWO<"';
      
      my $result = $str =~ s/$regex/$subst/rgee;
      
      print $result;
      

      表达式在this demo 的右上角进行了解释,如果您想探索/简化/修改它,在this link 中,您可以逐步观察它如何与一些示例输入匹配,如果你喜欢。

      【讨论】:

      • 请注意,Perl 在替换部分中只插入一次,即 $subst 将被插入,而不是 $1 它包含。
      • 它适用于my $subst = '"$1ONE$3TWO$5ONE$7TWO&lt;"';/rgee
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-25
      • 1970-01-01
      相关资源
      最近更新 更多