【问题标题】:Map with Split & Trim in Perl在 Perl 中使用拆分和修剪进行映射
【发布时间】:2011-03-10 22:20:21
【问题描述】:

如何使用带有 split 功能的 map 来修剪成分:$a、$b、$c 和 $d; $line 的?

my ($a, $b, $c, $d, $e) = split(/\t/, $line);

# Perl trim function to remove whitespace from the start and end of the string
sub trim($)
{
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

【问题讨论】:

    标签: perl map split trim


    【解决方案1】:

    除非你需要它们,否则不要在你的函数中使用原型($)

    my ( $a, $b, $c, $d, $e ) =
      map {s/^\s+|\s+$//g; $_}    ## Notice the `, $_` this is common
      , split(/\t/, $line, 5)
    ;
    

    不要忘记在上面的s/// 返回替换计数——而不是$_。所以,我们明确地这样做了。

    或更简单地说:

    my @values = map {s/^\s+|\s+$//g; $_}, split(/\t/, $line, 5), $line
    

    【讨论】:

    • 我不知道为什么投反对票,但你忘记了最后一行末尾的 g。
    • 为什么不推荐原型?
    • 阅读这个:stackoverflow.com/questions/297034/…,添加它,没有其他人这样做,它们会增加线路噪音。仅当您尝试创造一定水平的糖以使您具有不同的非腐烂外观或感觉时,您才需要它们。他们并没有真正处理其他事情,而且他们根本不处理方法。
    • 我建议map { s/^\s+|\s+$//gr } split('\t', $line)可以从perl 5.14使用
    【解决方案2】:

    map 接受两个输入:

    • 表达式或块:这将是 trim 表达式(您不必自己编写 - 它在 CPAN 上)
    • 和一个要操作的列表:这应该是split 的输出:
    use String::Util 'trim';
    my @values = map { trim($_) } split /\t/, $line;
    

    【讨论】:

    • 我对引入对“最终版本”的模块的依赖感到紧张。截至此版本,String::Util 不再处于开发或支持状态。
    • 如果我们要安装一个 CPAN 模块,我们不妨使用做得最好的那个:String::Strip。见illusori.co.uk/perl/2010/03/05/…
    • 我还没有尝试过,但是对这些模块的严格测试是它们是否会从字符串中去除像 Unicode 0x3000 这样的东西。如果不是,那么它可能不是一个好的替代品。看源码,String::Strip使用C函数isspace剥离空格,对unicode没有意识,所以会和上面的表现不一样。
    【解决方案3】:

    这应该可行:

    my ($a, $b, $c, $d, $e) = map {trim ($_)} (split(/\t/, $line));
    

    顺便说一句,这是一个小问题,但你不应该使用 $a 和 $b 作为变量名。

    【讨论】:

      【解决方案4】:

      你也可以在这里使用“foreach”。

      foreach my $i ($a, $b, $c, $d, $e) {
        $i=trim($i);
      }
      

      【讨论】:

        【解决方案5】:

        只为多样化:

        my @trimmed = grep { s/^\s*|\s*$//g } split /\t/, $line;
        

        grep 充当列表的过滤器。这就是为什么需要在正则表达式中将\s+s 更改为\s*s。强制匹配 0 个或多个空格可防止 grep 过滤掉列表中没有前导或尾随空格的项目。

        【讨论】:

        • 但它不包括被没有空格的制表符包围的段。 "\tspoon\t" 将被省略。
        • @Axeman : From perlretut: "\s 匹配空白字符、集合 [\ \t\r\n\f] 和其他字符。"此外,我们不是在\t这里分裂吗?)?
        • 是的——但没关系,我的眼睛把\s* 替换成了我平常的\s+。所以 subst 总是匹配的,我不知道我在说什么。 :D
        【解决方案6】:

        当我修剪字符串时,我通常不想保留原始字符串。拥有 sub 的抽象,但也不必为临时值大惊小怪。

        事实证明我们可以做到这一点,正如perlsub 解释的那样:

        传入的任何参数都显示在数组@_ 中。因此,如果你调用一个带有两个参数的函数,它们将存储在$_[0]$_[1] 中。数组@_ 是一个本地数组,但它的元素是实际标量参数的别名。特别是,如果元素 $_[0] 被更新,则相应的参数也会被更新(如果它不可更新,则会发生错误)。

        在你的情况下,trim 变为

        sub trim {
          for (@_) {
            s/^ \s+  //x;
            s/  \s+ $//x;
          }
          wantarray ? @_ : $_[0];
        }
        

        请记住,mapfor 是表亲,因此使用 trim 中的循环,您不再需要 map。例如

        my $line = "1\t 2\t3 \t 4 \t  5  \n";    
        my ($a, $b, $c, $d, $e) = split(/\t/, $line);    
        
        print "BEFORE: [", join("] [" => $a, $b, $c, $d), "]\n";
        trim $a, $b, $c, $d;
        print "AFTER:  [", join("] [" => $a, $b, $c, $d), "]\n";
        

        输出:

        之前:[1] [2] [3] [4]
        之后:[1] [2] [3] [4]

        【讨论】:

        • 你能解释一下join的'=>'用法吗?我以前从未见过?
        • @10rd_n3r0,我来试一试,join中的第一个参数是特殊的,其他的都是一样的,“胖逗号”(=>)只是比, 提供更好的视觉分离。出于这个原因,我自己使用过它。例如在这种情况下keyword => qw<a list of words> 在创建的列表中没有任何区别,但我正在展示我对它们的看法。在那些我希望视觉分离来描绘语义的时候,我使用 if。
        • @10rd 我用它来进行视觉分离,正如@Axeman 所描述的那样。在我写它的时候,我最初有join(", " => ...),每当分隔符包含逗号时,我喜欢使用粗逗号来提高可读性。
        • 更具可读性,也许:print "BEFORE: ". join ' ', map { '['.$_.']' } ($a, $b, $c, $d);
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-20
        • 2018-02-06
        • 1970-01-01
        • 2023-03-13
        • 2019-01-31
        相关资源
        最近更新 更多