在Perl的空白处拆分

时间:2015-02-17 14:45:54

标签: perl

我有类型的数据 -

500 3.6673656 
----------
1000 3.2707536
----------
1500 3.2356145
----------
2000 3.0495141
----------
2500 3.016674

即。时间和距离。 我需要将时间分成一个数组,将距离分成另一个数组。 通过使用my @line = split( /\s+/, $_);,我可以将距离存储在一个数组中,但无法存储时间。 有没有其他方法可以将它们分别存储在不同的数组中?

输入来自文件,内容存储在@array

我的剧本:

    foreach $_ (@array){ 
    if($_ =~ /[@]/) {# do nothing, it's a comment or formatting line} 
    else  {my @line = split( /\s+/, $_);
    print "@line\n";}
}

6 个答案:

答案 0 :(得分:6)

让我们得到所有花哨的裤子:

#! /usr/bin/env perl
#

use strict;
use warnings;
use feature qw(say);

my @array;
while ( my $line = <DATA> ) {
    chomp $line;
    push @array, $line;
}

#
# As two separate arrays (Not so good)
#
my @times;
my @distances;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next if $entry =~ /--+$/;   # Next if all dashes
    my ( $distance, $time ) = split /\s+/, $entry;
    push @times, $time;
    push @distances, $distance;
}
say "The first entry as two distinct arrays";
say "Distance: $distances[0]";
say "Time: $times[0]";

#
# As two entries in a single array
#
my @velocities;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next if $entry =~ /--+$/;   # Next if all dashes
    my @velocity = split /\s+/, $entry;
    push @velocities, \@velocity;
}
say "The first entry as an array of arrays";
say "Distance: " . $velocities[0]->[0];
say "Time: " . $velocities[0]->[1];
#
# As a hash in an array (Better Still)
# Note: Using regular expression to split
#
my @velocities2;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next unless $entry =~ /\s*(\S+)\s+(\S+)/;
    my %velocity;
    $velocity{DISTANCE} = $1;
    $velocity{TIME} = $2;
    push @velocities2, \%velocity;
}
say "The first entry as an array of hashes";
say "Distance: " . $velocities2[0]->{DISTANCE};
say "Time: " . $velocities2[0]->{TIME};
#
# As objects (The best!)
#
my @velocities3;
for my $entry ( @array ) {
    chomp $entry;               # Not needed, but never hurts
    next unless $entry =~ /\s*(\S+)\s+(\S+)/;
    my $distance = $1;
    my $time = $2;
    my $velocity = Local::Velocity->new( $distance, $time );
    push @velocities3, $velocity;
}
say "The first entry as an object";
say "Distance: " . $velocities3[0]->distance;
say "Time: " . $velocities3[0]->time;

package Local::Velocity;

sub new {
    my $class    = shift;
    my $distance = shift;
    my $time     = shift;

    my $self = {};
    bless $self, $class;
    $self->distance( $distance );
    $self->time( $time );
    return $self;
}

sub distance {
    my $self     = shift;
    my $distance = shift;

    if ( defined $distance ) {
        $self->{DISTANCE} = $distance;
    }
    return $self->{DISTANCE};
}

sub time {
    my $self    = shift;
    my $time    = shift;

    if ( defined $time ) {
        $self->{TIME} = $time;
    }
    return $self->{TIME};
}

package main;
__DATA__
500 3.6673656 
----------
1000 3.2707536
----------
1500 3.2356145
----------
2000 3.0495141
----------
2500 3.016674

第一种方式是你问的:两个并行数组。此方法的问题在于您现在必须按顺序保留两个单独的数据结构。如果传递时间和距离,则必须传递两个单独的数据元素。如果修改一个,则必须修改另一个。如果您从一个pushpop,则必须对另一个进行。

只有两个,但不要太糟糕,但想象一下这么做十几个或更多。

第二种方式使用References。引用允许您执行更复杂的数据结构。这将两个条目保持在一个阵列中。现在,您有一个包含两个条目的数组。 push一个,而你push另一个。 pop一个,而你pop另一个。如果将时间和距离传递给子程序,则只需传递一个条目。

第三种方式将参考概念提升了一个档次。您可以使用哈希,而不是使用数组来存储您的两个值。优点是散列中的每个元素都有一个名称。第一个入口或第二个入口是距离吗?没关系,这是标有DISTANCE的条目。与数组或数组相同的优点,但现在,您标记哪个是哪个。想象一个有姓名,电话,地址等的人,你可以看到它的优势。

最后一种方法是使用objects。您可以看到与使用哈希非常相似。您没有哈希或数组。您有一个包含时间和距离的Local::Velocity对象。

看起来有点复杂,但对象有很多优点:

  • 条目是DISTANCEDistance还是distance没有问题,并且没有拼写错误distanse的问题。您有一个名为distance方法。弄清楚这个名字,你的程序尽职尽责地崩溃,而不是继续处理坏数据。
  • 您可以在不影响程序的情况下修改对象。例如,可能是一个名为velocity的子程序,它接收您的对象并返回速度。或许您可能想要为速度添加方向。修改对象不会影响您的程序。

面向对象的Perl允许您创建极其复杂的数据类型,而无需记住您如何构建它们。这就是为什么大多数新模块都是面向对象的。

答案 1 :(得分:5)

分割线和存储数据是微不足道的。您希望如何存储它以供以后使用是个问题。您可以在空格上拆分行并将其存储为:

my @data =  map { [ split ] } @lines;

split的默认调用,在空格上分割 $_

接下来,您可以省略'@'带grep:

的那些行
my @data = map { [ split ] } grep { index( $_, '@' ) == -1 } @lines;

这里只是最简单的存储结构:

use strict;
use warnings;
use constant TIME     => 0;
use constant DISTANCE => 1;

my @data = map { [ split ] } grep { index( $_, '@' ) == -1 } @lines;

然后,您可以按插槽名称处理不同的字段。

foreach my $row ( @data ) {
    printf "At time : %d, distance was %f\n", $row->[TIME], $row->[DISTANCE];
}

答案 2 :(得分:4)

你可以这样做:

my (@times, @dists);
foreach (@array) { 
    if (/[@]/) {
        # do nothing, it's a comment or formatting line
    } 
    else  {
        my ($time, $dist) = split( /\s+/, $_);
        push @times, $time;
        push @dists, $dist;
    }
}

答案 3 :(得分:2)

您可以使用正常的split命令。只需将结果保存在两个变量中,并将push保存到两个不同的数组中。

my (@times, @distances);
foreach my $line (@array) {
  next if $line eq '----------'; # skip lines with lines (no pun intended)
  my ($t, $d) = split /\s/, $line;
  push @times, $t;
  push @distances, $d;
}

答案 4 :(得分:2)

做你认为你想做的事很容易。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

my (@distance, @time);

while (<DATA>) {
  next if /----/;
  chomp;

  my ($t, $d) = split; # Splits on whitespace by default
  push @distance, $d;
  push @time, $t;
}

say "@distance";
say "@time";

__DATA__
500 3.6673656 
----------
1000 3.2707536
----------
1500 3.2356145
----------
2000 3.0495141
----------
2500 3.016674

然而,这是一个非常糟糕的主意。输入每行的距离和时间显然是相互关联的。因此,将它们存储在单独的变量中是一个坏主意,其中两个值之间的关系由它们在不同数组中具有相同索引的事实表示。

更好的方法是将两个值存储在一起(可能在哈希中)并存储这些哈希值(或者更确切地说,是对数组中哈希值的引用。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Data::Dumper;

my (@data);

while (<DATA>) {
  next if /----/;
  chomp;

  my %row;

  @row{qw[time distance]} = split; # Splits on whitespace by default
  push @data, \%row;
}

say Dumper \@data;

__DATA__
500 3.6673656 
----------
1000 3.2707536
----------
1500 3.2356145
----------
2000 3.0495141
----------
2500 3.016674

答案 5 :(得分:1)

请看一下这个例子:

use strict;
use warnings;
use Data::Dumper;

my $str=<<EOF;
500 3.6673656
1000 3.2707536
1500 3.2356145
2000 3.0495141
2500 3.016674
EOF

my @arr= split /\n/, $str;
my @arr1;
my @arr2;

foreach (@arr) {
    chomp;
    my $line = $_;
    next if ($line=~/^\s*$/);
    my ($val1,$val2) = $line=~/(\S+)\s+(\S+)/;
    push @arr1,$val1;
    push @arr2, $val2;
}

print Dumper (\@arr1);
print Dumper (\@arr2);
相关问题