如何将Perl的分割命令与空格修剪结合使用?

4

从Perlmonks转载,内容涉及IT技术。

我写了一个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";
}

2
你尝试过:split /\s*;\s*/, $file_data 吗? - C. K. Young
我认为你也可以使用unpack(),但我现在无法尝试它,而且我对unpack()的理解不足以在没有它的情况下为你提供解决方案。 - Makis
7个回答

11
如果你不需要去掉第一个和最后一个元素,那么这个方法可以解决问题:
@email_list = split /\s*;\s*/, $file_data;

如果你确实需要删除第一个和最后一个元素,先修整$file_data,然后按上述方法重复即可。:-P


11

你并不需要在同一个函数中同时完成这两个操作。有时分步进行会更加清晰明了。也就是说,先进行分割,然后去除每个元素的空格(最后再对结果进行排序):

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

编辑:同时剥离字符串中多个部分可能会导致问题,例如Sinan在下面指出的在“Elizabeth”部分中保留尾随空格的情况。我编写了该代码片段,假设名称不会有内部空格,这实际上是非常错误的,如果我有意识地注意到它,那么它就会显得不正确。下面的代码改进了很多(也更易读):

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

显然在注释中不能有多个空格,但是在 Elizabeth 之后有四个空格。 - Sinan Ünür
首先...其次...非常好的观点!上面的回复已经编辑过了。 - Ether

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";
}

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

1

请参阅FAQ中的如何从字符串开头/结尾删除空格?

@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+$//;
}

这也可以工作。


0

轮到我了:

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

这是最可靠的方法。


-1
除了一些小的语法错误外,这应该能为您完成整个工作。哦,列表操作,你是多么美丽啊!
print join (" \n", sort { $a <=> $b } map { s/^[ \t]+|[ \t]+$//g } split (/;/, $file_data));

1
使用 map 返回 s/// 的结果并不是很有用。尝试使用 map { s/...//g; $_ }。 - ysth
你可能不是指数字排序。 - ysth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接