【问题标题】:Perl do substitution in substitution itselfPerl 在替换本身中进行替换
【发布时间】:2020-02-28 18:14:51
【问题描述】:

我正在使用 Perl 对 html sn-p 进行一些正则表达式替换操作。

这就是我匹配想要的部分的方式:(class="p_hw"><a href=")(http://[^<>"]*?xxxx\.com\/[^<>"]*[=/])([^<>"]*)(">(?:<b>)?)(.*?)(?=<)

我需要用entry:// 替换http:// 后跟http url 的某些参数值($3 就此而言)如果该值存在于哈希中(%hw_f),否则第一个单词来自$5 的(或短语)将在它存在于%hw_f 时使用。如果所有条件都不匹配,sn-p 将保持不变。

我尝试了以下方法:

s#(class="p_hw"><a href=")(http://[^<>"]*?xxxx\.com\/[^<>"]*[=/])([^<>"]*)(">(?:<b>)?)(.*?)(?=<)#
        my @n = split(/\,|;/, $5);
    my @m = map {s,^\s+|\s+$,,mgr} @n;
    my $new = $3 =~ s/^\s+|\s+$//mgr;
    my $new2 = $new =~ s/\+/ /mgr;
    exists $hw_f{$new2} ? "$1entry://$new2$4$5" : (exists $hw_f{$m[0]} ? "$1entry://$m[0]$4$5" : "$1$2$3$4$5") #eg;

%hw_f 是匹配所有条件的地方。

它给出了以下错误:

在连接 (.) 或字符串中使用未初始化的值 $1

我需要在替换中基于$3 获得一个新值,继续使用该新值。我怎么能这样做?

【问题讨论】:

  • 每次调用正则表达式引擎都会破坏捕获变量的先前状态。您需要在拆分之前将 $3 复制到一个新变量中。
  • 你的意思是 5 美元吗?我分了 5 美元。 @DavidO
  • 我试过dclone把$3放到一个数组里,也没用。
  • 你没有说你想做什么。如果您尝试返回原始$3,则需要对其进行备份,因为后者的匹配和替换会清除或替换其值。 s#...# my $three = $3; ...; $three 3#eg。但这不可能是您想要做的,因为您从不使用@m$new2。那你想做什么?也许你应该返回$new2 而不是$3???
  • 您的第一个替换 s#...## 捕获到 3 美元。您的拆分再次调用了正则表达式引擎(这就是 /.../ 的用途)。所以拆分 clobbers 3 美元。但即使它没有(它确实如此),你的下一行,map{s,...,,} 确实会减少 3 美元。你不需要 dclone 它。您只需要在分割线之前使用赋值运算符 (=) 将 $3 复制到其他变量,然后稍后使用它而不是依赖 $3。

标签: regex perl


【解决方案1】:

从您的帖子来看,您试图实现的目标并不明显。如果您将问题描述为以下格式会更容易理解

--- 示例 -----------

我从网页中提取带有&lt;a href="http:\\....... 的sn-p,我想将其转换/转换为以下格式&lt;a href="http:\\.......

至少通过这种方式我们知道什么是 INPUT 以及 OUTPUT 期望什么。

--- 例子结束------------

当您使用 memory 应用正则表达式时,将 remembered 值存储在数组或更好的哈希中会更容易

use strict;
use warnings;

use Data::Dumper;

my %href;

$data = shift;

if( $data =~ /<a href="(\w+):\\\\([\w\d\.]+)\\([\w\d\.]+)\\(.+)">([^<]+)</ ) {
    @href{qw(protocol dns dir rest desc)} = ($1,$2,$3,$4,$5);
    print Dumper(\%href);
} else {
    print "No match found\n";
}

【讨论】:

    【解决方案2】:

    更新:

    while (<DICT>) {
    s#(class="p_hw"><a href=")(http://[^<>"]*?wordinfo\.info\/[^<>"]*[=/])([^<>"]*)(">(?:<b>)?)(.*?)(?=<)#
            my $one = $1;
        my $two = $2;
        my $three = $3;
        my $four = $4;
        my $five = $5;
            my @n = split(/\,|;/, $5);
        my @m = map {s,^\s+|\s+$,,mgr} @n;
        my $new = $3 =~ s/^\s+|\s+$//mgr;
        my $new2 = $new =~ s/\+/ /mgr;
        exists $hw_f{$new2} ? $one."entry://$new2$four$five" : (exists $hw_f{$m[0]} ? $one."entry://$m[0]$four$five" : "$one$two$three$four$five") #eg;
    
        print $FH $_;
    }
    

    在提到的评论中将所有正则表达式引擎调用之前的所有捕获变量分配为@DavidO,它终于可以工作了。谢谢。

    【讨论】:

      【解决方案3】:

      我不会尝试真正修复您尝试完成的逻辑,因为这是相当不明智的。我要做的是提供一些语义和编码建议。

      1:使用 Regexp::Common 和 URI 处理 URL。编写自己的正则表达式几乎不值得。使用正则表达式解析 HTML 要求您认真了解自己在做什么。 https://metacpan.org/search?q=regexp%3A%3Acommon

      2: 始终只使用 {} 和 // 来包装正则表达式。 (99% 的规则)

      3:除非表达式很简单,否则总是立即将编号变量复制到有意义命名的 my() 变量中。

      4:使用后缀 foreach 就地修改数组。

      5:分散代码格式以使其具有视觉吸引力。

      6:使用 sprintf 进行复杂的变量重组。它可以更轻松地查看在何处使用了哪些变量以及用于什么目的。

      HTH

      #  1                        2                                     3        4           5
      s{(class="p_hw"><a href=\")(http://[^<>"]*?xxxx\.com/[^<>"]*[=/])([^<>\"]*)(\">(?:<b>)?)(.*?)(?=<)}{
          my ($m1, $m2, $m3, $m4, $m5) = ($1, $2, $3, $4, $5);
          my @n = split /[,|;]/, $m5;
          s/^\s+|\s+$//mg foreach @n;
          (my $new = $m3) =~ s/^\s+|\s+$//mg;
          (my $new2 = $new) =~ s/\+/ /g;
          exists $hw_f{$new2} ?
              sprintf "%sentry://%s%s%s", $m1, $new2, $m4, $m5 :
              exists $hw_f{$n[0]} ? 
              sprintf "%sentry://%s%s%s", $m1, $n[0], $m4, $m5 :
              "$m1$m2$m3$m4$m5";
      }ige;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-13
        • 2017-01-05
        • 2011-02-15
        • 1970-01-01
        • 1970-01-01
        • 2012-01-30
        相关资源
        最近更新 更多