【问题标题】:How can I combine Perl's split command with white space trimming?如何将 Perl 拆分命令与空白修剪结合起来?
【发布时间】:2010-11-18 16:54:21
【问题描述】:

Repost from Perlmonks 给同事:

我编写了一个 perl 脚本来分隔由分号分隔的长电子邮件列表。我想对代码做的是将拆分与空白的修剪结合起来,所以我不需要两个数组。加载第一个数组时是否需要修剪。输出是名称的排序列表。 谢谢。

#!/pw/prod/svr4/bin/perl
use warnings;
use strict;

my $file_data =
  'Builder, Bob  ;Stein, Franklin MSW; Boop, Elizabeth PHD   Cc: Bear,
+ Izzy';
my @email_list;

$file_data =~ s/CC:/;/ig;
$file_data =~ s/PHD//ig;
$file_data =~ s/MSW//ig;

my @tmp_data = split( /;/, $file_data );

foreach my $entry (@tmp_data) {
    $entry =~ s/^[ \t]+|[ \t]+$//g;
    push( @email_list, $entry );
}

foreach my $name ( sort(@email_list) ) {
    print "$name \n";
}

【问题讨论】:

  • 你试过了吗:split /\s*;\s*/, $file_data
  • 我认为你也可以使用 unpack(),但我现在不能尝试,而且我没有足够的了解 unpack() 来为你提供没有它的解决方案。

标签: perl split


【解决方案1】:

如果您不需要修剪第一个和最后一个元素,这将解决问题:

@email_list = split /\s*;\s*/, $file_data;

如果确实需要修剪第一个和最后一个元素,请先修剪$file_data,然后重复上述操作。 :-P

【讨论】:

    【解决方案2】:

    好吧,你可以按照 Chris 的建议去做,但它不处理 $file_data 中的前导和尾随空格。

    您可以像这样添加对这些的处理:

    $file_data =~ s/\A\s+|\s+\z//g;
    

    另外,请注意不需要使用第二个数组。检查这个:

    my $file_data = 'Builder, Bob  ;Stein, Franklin MSW; Boop, Elizabeth PHD   Cc: Bear, Izzy';
    my @email_list;
    
    $file_data =~ s/CC:/;/ig;
    $file_data =~ s/PHD//ig;
    $file_data =~ s/MSW//ig;
    
    my @tmp_data = split( /;/, $file_data );
    
    foreach my $entry (@tmp_data) {
        $entry =~ s/^[ \t]+|[ \t]+$//g;
    }
    
    foreach my $name ( sort(@tmp_data) ) {
        print "$name \n";
    }
    

    【讨论】:

      【解决方案3】:

      除非出现一些小的 sintax 错误,否则这应该会为您完成全部工作。哦,列表操作,你多美啊!

      print join (" \n", sort { $a <=> $b } map { s/^[ \t]+|[ \t]+$//g } split (/;/, $file_data));
      

      【讨论】:

      • 让 map 返回 s/// 的结果不是很有用。试试 map { s/...//g; $_ }
      • 你可能不是指数字排序。
      【解决方案4】:

      您不必使用同一个函数一次性完成这两项操作。有时单独执行操作会更清楚。也就是说,先拆分,然后去除每个元素的空白(然后对结果进行排序):

      @email_list =
          sort(
              map {
                      s/\s*(\S+)\s*/\1/; $_
                  }
                  split ';', $file_data
          );
      

      编辑:同时剥离字符串的多个部分可能会导致陷阱,例如下面是思南关于在“伊丽莎白”部分留下尾随空格的观点。我对这个 sn-p 进行了编码,假设该名称不会有内部空格,这实际上是完全错误的,如果我有意识地注意到它,它会被认为是不正确的。代码在下面得到了很大改进(并且更具可读性):

      @email_list =
          sort(
              map {   
                      s/^\s+//;  # strip leading spaces
                      s/\s+$//;  # strip trailing spaces
                      $_         # return the modified string
                  }
                  split ';', $file_data
          );
      

      【讨论】:

      • 显然在 cmets 中不能有多个空格,但在 Elizabeth 之后有空格。
      • > 第一个...第二个...非常好的点!上面的编辑回复。
      【解决方案5】:
      my @email_list = map { s/^[ \t]+|[ \t]+$//g; $_ } split /;/, $file_data;
      

      或者更优雅的:

      use Algorithm::Loops "Filter";
      my @email_list = Filter { s/^[ \t]+|[ \t]+$//g } split /;/, $file_data;
      

      【讨论】:

        【解决方案6】:

        轮到我了:

        my @fields = grep { $_ } split m/\s*(?:;|^|$)\s*/, $record;
        

        它还去除了第一个和最后一个元素。如果 grep 对于摆脱第一个元素来说太过分了:

        my ( undef, @fields ) = split m/\s*(?:;|^|$)\s*/, $record;
        

        如果您知道有空格,则可以使用,但这不太可能,所以

        my @fields = split m/\s*(?:;|^|$)\s*/, $record;
        shift @fields unless $fields[0];
        

        是最可靠的方法。

        【讨论】:

          【解决方案7】:

          请参阅常见问题解答中的How do I strip blank space from the beginning/end of a string?

          @email_list = sort map {
              s/^\s+//; s/\s+$//; $_
          } split ';', $file_data;
          

          现在,还要注意 for 循环为数组的每个元素设置别名,所以

          @email_list = sort split ';', $file_data;
          
          for (@email_list) {
              s/^\s+//;
              s/\s+$//;
          }
          

          也可以。

          【讨论】:

            猜你喜欢
            • 2014-08-25
            • 1970-01-01
            • 1970-01-01
            • 2013-10-21
            • 2010-11-14
            • 2021-04-06
            • 1970-01-01
            • 1970-01-01
            • 2012-02-08
            相关资源
            最近更新 更多