簡體   English   中英

如何對這個替換的Perl子程序進行高爾夫?

[英]How can I golf this Perl subroutine that does a substitution?

我在Perl中有以下子程序用“abc”替換字符串中的“xyz”:

sub mySubst {
    my ($str) = @_;
    $str =~ s|abc|xyz|ig;
    return $str;    
}

它有效,但對於Perl來說似乎太冗長了。 我怎樣才能把它收緊?

你有什么好。

  • 您使用列表賦值從@_變量中拉出參數,進行復制。 列表賦值是一種很好的方法(基本上是標准方式。)使用shift也可以工作,但是更改@_(可能是也可能不是你想要的。) 有關PerlMonks的討論關於轉換vs @_你可能會感興趣。
  • 您在搜索和替換時使用命名變量。 在這種情況下,我更喜歡命名變量,因為處理Perl的魔術變量需要注意。
  • 可以自動處理$ _,但是沒有$ _自動填充會使得更難以正確使用。 你需要做local $_ = shift; local ($_) = @_; 這不會增加太多。)
  • 當人們使用明確的return時,我喜歡它。 這是一個溫暖的模糊。
  • K&R Brackets。 好。 :)
  • 沒有原型。 很好。 :)

去吧。 我認為你走在正確的軌道上。

如果您正在尋找高爾夫,而不是生產代碼。

use strict;   ## Not really required ;)
use warnings; ## Not really required ;)
sub f{local$_=pop,s/foo/bar/ig;$_}
print f 'foobarbaz';

你可以寫:

sub mySubst { (map { s|abc|xyz|ig; $_ } "$_[0]" )[0] }

但除非這是一個混淆的練習,否則我會說你有你的東西。 請記住,您沒有為計算機編寫程序。

這是我如何更慣用地渲染該子例程:

sub mySubst {
    (my $str = shift) =~ s|abc|xyz|ig;
    return $str;
}

我覺得太冗長的聲音就像我不同意的那樣混淆不夠 至於收緊它,我建議采取以下措施:

sub replaceBeginningWithEnd {
    my $text = shift;
    return if not defined($text);
    $text =~ s/abc/xyz/ig;
    return $text;    
}
  • 使名稱更具可讀性
  • 使用約定(即。/與|相反)
  • 參數檢查

沒有人為此提供Perl成語。 這通過修改副本來復制原始代碼的行為:

  (my $new_str = $old_str) =~ s/abc/xyz/ig;

如果我不得不把它放到一個子程序中,我認為這對於這么簡單的操作來說有點傻,我想那會是:

 sub foo { (my $s = $_[0]) =~ s/abc/xyz/ig; $s }

但是,如果我這樣做傻事,我就不會為它做一個命名的子程序。 我做了一個子程序來為我創建子程序,所以我不需要為每種可能的替換方式添加一個新的命名子:

 sub make_sub {
      my( $regex, $replacement ) = @_;

      # season to taste with error checking
      sub {
          (my $s = $_[0]) =~ s/$regex/$replacement/ig; $s
          };
      }

 my $replacer = make_sub( qr/abc/, 'xyz' );

 my $new = $replacer->( $string );

什么是子? 就這樣做吧

$str =~ s|abc|xyz|ig;

您可以省略return關鍵字:

sub mySubst {
    my ($str) = @_;
    $str =~ s|abc|xyz|ig;
    $str;    
}

也可以使用默認變量( $_ ):

sub mySubst {
    local $_ = shift;  # or my starting from Perl 5.10
    s|abc|xyz|ig;
    $_;    
}

為避免更改原件,您可以寫

sub mySubst { map { (my $s=$_) =~ s|abc|xyz|ig; $s } @_ }

要么

sub mySubst { my @a = @_; map { s|abc|xyz|ig; $_ } @a }

或借用思南的答案,除了明確丟棄臨時陣列:

sub mySubst { map { s|abc|xyz|ig; $_ } my(undef) = @_ }

但語法仍然有點吵。 因為它使用map ,所以一定要在列表上下文中調用它:

my($result) = mySubst $str;  # NOT my $one = mySubst $str;

如果您希望主要使用單個參數調用mySubst但想要處理一個或多個參數的情況,那么您可以編寫

sub mySubst {
  s|abc|xyz|ig for my @a = @_;
  wantarray ? @a : $a[0];
}

但這又開始了口吃。


如果你要更新的參數本身,使用Perl的潛艇別名語義中記錄perlsub

數組@_是一個本地數組,但它的元素是實際標量參數的別名。 特別是,如果更新元素$_[0]則更新相應的參數(如果不可更新,則會發生錯誤)。

所以你可以寫

sub mySubst { $_[0] =~ s|abc|xyz|ig }

甚至

sub mySubst { map { s|abc|xyz|ig; $_ } @_ }

用法示例:

$str = "fooabcbar";
mySubst $str;
print $str, "\n";

輸出:

fooxyzbar

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM