简体   繁体   English

如何对这个替换的Perl子程序进行高尔夫?

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

I have the following subroutine in Perl to substitute "abc" for "xyz" in a string: 我在Perl中有以下子程序用“abc”替换字符串中的“xyz”:

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

It works, but seems way too verbose for Perl. 它有效,但对于Perl来说似乎太冗长了。 How can I tighten it up? 我怎样才能把它收紧?

What you have is fine. 你有什么好。

  • You pull the arguments off the @_ variable, making a copy, using a list assignment. 您使用列表赋值从@_变量中拉出参数,进行复制。 List assignment is an excellent way to do it (and basically the standard way.) Using shift would also work, but changes @_ (may or may not be what you want.) There's a discussion on PerlMonks about shift vs @_ that you might be interested in. 列表赋值是一种很好的方法(基本上是标准方式。)使用shift也可以工作,但是更改@_(可能是也可能不是你想要的。) 有关PerlMonks的讨论关于转换vs @_你可能会感兴趣。
  • You use a named variable with your search and replace. 您在搜索和替换时使用命名变量。 I prefer named variables in this case, since dealing with Perl's magic variables takes care. 在这种情况下,我更喜欢命名变量,因为处理Perl的魔术变量需要注意。
  • Automatically working on $_ would be possible, but not having $_ auto populated makes it trickier to get right. 可以自动处理$ _,但是没有$ _自动填充会使得更难以正确使用。 You'd need to do local $_ = shift; 你需要做local $_ = shift; or local ($_) = @_; local ($_) = @_; which doesn't add much.) 这不会增加太多。)
  • I like it when people use an explicit return . 当人们使用明确的return时,我喜欢它。 It's a warm fuzzy. 这是一个温暖的模糊。
  • K&R Brackets. K&R Brackets。 Good. 好。 :) :)
  • No prototype. 没有原型。 Very good. 很好。 :) :)

Go with it. 去吧。 I think you're on the right track. 我认为你走在正确的轨道上。

If you're looking for golf, and not production code. 如果您正在寻找高尔夫,而不是生产代码。

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

You could write: 你可以写:

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

but unless this is an exercise in obfuscation, I would say go with what you have. 但除非这是一个混淆的练习,否则我会说你有你的东西。 Remember, you are not writing the program for the computer. 请记住,您没有为计算机编写程序。

This is how I would render that subroutine more idiomatically: 这是我如何更惯用地渲染该子例程:

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

I think too verbose sounds like not enough obfuscation which I disagree. 我觉得太冗长的声音就像我不同意的那样混淆不够 As for tightening it up I'd suggest something along the lines of: 至于收紧它,我建议采取以下措施:

sub replaceBeginningWithEnd {
    my $text = shift;
    return if not defined($text);
    $text =~ s/abc/xyz/ig;
    return $text;    
}
  • Make names more readable 使名称更具可读性
  • Use conventions (ie. / as oppose to |) 使用约定(即。/与|相反)
  • Argument checking 参数检查

No one gave the Perl idiom for this yet. 没有人为此提供Perl成语。 This replicates the behavior of the original code by modifiying a copy: 这通过修改副本来复制原始代码的行为:

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

If I had to put that into a subroutine, which I think is kinda silly for such a simple operation, I guess that would be: 如果我不得不把它放到一个子程序中,我认为这对于这么简单的操作来说有点傻,我想那会是:

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

However, if I was doing something silly like this, I wouldn't make a named subroutine for it. 但是,如果我这样做傻事,我就不会为它做一个命名的子程序。 I'd make a subroutine to make the subroutine for me so I don't need a new named sub for every possible sort of replacement: 我做了一个子程序来为我创建子程序,所以我不需要为每种可能的替换方式添加一个新的命名子:

 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 );

what is the sub for? 什么是子? just do it like this 就这样做吧

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

You can omit the return keyword: 您可以省略return关键字:

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

It is also possible to use the default variable ( $_ ) : 也可以使用默认变量( $_ ):

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

To avoid changing the originals, you could write 为避免更改原件,您可以写

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

or 要么

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

or to borrow from Sinan's answer, except discarding the temporary array explicitly: 或借用思南的答案,除了明确丢弃临时阵列:

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

but the syntax is still a little noisy. 但语法仍然有点吵。 Because it uses map , be sure to call it in list context: 因为它使用map ,所以一定要在列表上下文中调用它:

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

If you expect to mostly call mySubst with a single argument but want to handle cases of one or more arguments, then you could write 如果您希望主要使用单个参数调用mySubst但想要处理一个或多个参数的情况,那么您可以编写

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

but that starts up the stuttering again. 但这又开始了口吃。


If you want to update the parameter itself, use the alias semantics of Perl's subs as documented in perlsub : 如果你要更新的参数本身,使用Perl的潜艇别名语义中记录perlsub

The array @_ is a local array, but its elements are aliases for the actual scalar parameters. 数组@_是一个本地数组,但它的元素是实际标量参数的别名。 In particular, if an element $_[0] is updated, the corresponding argument is updated (or an error occurs if it is not updatable). 特别是,如果更新元素$_[0]则更新相应的参数(如果不可更新,则会发生错误)。

So you could write 所以你可以写

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

or even 甚至

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

Example usage: 用法示例:

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

Output: 输出:

fooxyzbar

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM