【问题标题】:Perl Regex : Modification of a read-only value attemptedPerl Regex:尝试修改只读值
【发布时间】:2012-09-11 13:28:17
【问题描述】:

在将字符串与正则表达式匹配后,我试图替换字符串中的whitespaces

my $string = "watch download Buffy the Vampire Slayer Season 1 Episode 1 Gorillavid";

if ($string =~ m!(Season\s\d+\sEpisode\s\d+)!){

    $1 =~ s!\s+!!g;

    say $1;

}

现在当我运行上面的代码时,我得到了Modification of a read-only value attempted。现在,如果我将 $1 的值存储在一个变量中,而不是尝试对该变量执行替换,它就可以正常工作。

那么,有什么方法可以在不创建新临时变量的情况下就地执行替换。

PS:有人可以告诉我如何将上面的代码写成单行代码,因为我不能:)

【问题讨论】:

  • 你期待什么结果?只是“Season1Episode1”,没有其他字符串?
  • 你不能只做say s!\s+!!g;吗?
  • @qnan 那只会说 1。您可以使用 /r 修饰符,尽管这需要 v5.14。此外,您需要将值放入另一个变量中。

标签: regex perl


【解决方案1】:

不要乱用特殊变量,只捕获你想要的数据,自己构建输出。

$string = "watch download Buffy the Vampire Slayer Season 1 Episode 1 Gorillavid";
if ($string =~ m!Season\s(\d+)\sEpisode\s(\d+)!){
   say("Season$1Episode$2");
}

【讨论】:

    【解决方案2】:

    您似乎想在原始字符串中将Season 1 Episode 1 压缩为Season1Episode1

    这可以通过使用@-@+ 以及调用substr 作为左值来方便地完成

    这个程序显示了这个想法

    use strict;
    use warnings;
    
    my $string = "watch download Buffy the Vampire Slayer Season 1 Episode 1 Gorillavid";
    
    if ($string =~ /Season\s+\d+\s+Episode\s+\d+/ ) {
    
      substr($string, $-[0], $+[0] - $-[0]) =~ s/\s+//g;
      print $string;
    }
    

    输出

    watch download Buffy the Vampire Slayer Season1Episode1 Gorillavid
    

    你没有说为什么要在一行中写这个,但如果你必须这样做,那么它会为你做的

    perl -pe '/Season\s*\d+\s*Episode\s*\d+/ and substr($_, $-[0], $+[0] - $-[0]) =~ s/\s+//g' myfile
    

    【讨论】:

    • 在哪里可以找到@- and @+ 的相关文档。
    • @RanRag:查看here 并搜索@LAST_MATCH_START@LAST_MATCH_END
    • @RanRag perldoc -v @-(使用适当的引用来避免 shell 插值。)
    【解决方案3】:

    如果您使用后置脚本for 循环来创建$_ 的本地实例,您可以将替换与打印链接(使用逗号)以实现匹配的预打印处理。

    请注意,使用全局 /g 选项时不需要括号。另请注意,这会使您的 if 语句变得多余,因为任何不匹配都会向您的 for 循环返回一个空列表。

    perl -nlwe 's/\s+//g, print for /Season\s+\d+\s+Episode\s+\d+/g;' yourfile.txt
    

    在您的脚本中,它看起来像这样。请注意,if 语句已替换为 for 循环。

    for ( $string =~ /Season\s+\d+\s+Episode\s+\d+/g ) {
        s/\s+//g;  # implies $_ =~ s/\s+//g
        say;       # implies say $_
    
    }
    

    这里主要是为了演示单线。您可以插入一个词法变量而不是使用$_,例如for my $match ( ... ) 如果您想提高可读性。

    【讨论】:

      【解决方案4】:
      $string =~ s{(?<=Season)\s*(\d+)\s*(Episode)\s*(\d+)}{$1$3$2};
      

      【讨论】:

        【解决方案5】:

        你可以试试这个:

        perl -pi -e 'if($_=~/Season\s\d+\sEpisode\s\d/){s/\s+//g;}' file
        

        测试如下:

        XXX> cat temp
        watch download Buffy the Vampire Slayer Season 1 Episode 1 Gorillavid
        XXX> perl -pi -e 'if($_=~/Season\s\d+\sEpisode\s\d/){s/\s+//g;}' temp
        XXX> cat temp
        watchdownloadBuffytheVampireSlayerSeason1Episode1GorillavidXXX>
        

        【讨论】:

        • 当解决方案正确时为什么会有反对票。如您所见,修改是内联完成的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-09
        相关资源
        最近更新 更多