FAQ
Hello Perl guru's,
I need to pull multiple values form an array. There are
separator array entries. I need to be able to get all the values between
the separator values, process them, and then move onto the next group
till the end. Here is an example of the array.

========================================================================
========
media ID: 001070
media type: 1/2" cartridge tape (6)
barcode: 001070
media description: V0|256|S190|20040315
volume pool: NBdatabase (5)
robot type: NONE - Not Robotic (0)
volume group: Offsite-V0
vault name: V0
vault sent date: Thu Jan 17 21:23:12 2008
vault return date: Thu Jan 31 19:51:59 2008
vault slot: 5038
vault session id: 8314
vault container id: -
created: Wed Feb 28 18:55:26 2001
assigned: Thu Jan 17 19:51:59 2008
last mounted: Thu Jan 17 20:58:00 2008
first mount: Wed Feb 28 19:01:24 2001
expiration date: ---
number of mounts: 148
max mounts allowed: ---
status: 0x1
========================================================================
========
media ID: 001071
media type: 1/2" cartridge tape (6)
barcode: 001071
media description: V0|432|S3840|00000000
volume pool: NBdatabase (5)
robot type: NONE - Not Robotic (0)
volume group: Offsite-V0
vault name: V0
vault sent date: Fri Jan 18 02:35:30 2008
vault return date: Fri Feb 01 00:01:26 2008
vault slot: 4884
vault session id: 8316
vault container id: -
created: Wed Feb 28 19:50:06 2001
assigned: Fri Jan 18 00:01:25 2008
last mounted: Fri Jan 18 01:23:39 2008
first mount: Wed Feb 28 20:01:38 2001
expiration date: ---
number of mounts: 141
max mounts allowed: ---
status: 0x1
========================================================================
========
media ID: 001072
media type: 1/2" cartridge tape (6)
barcode: 001072
media description: V0|368|S5180|00000000
volume pool: NBdatabase (5)
robot type: NONE - Not Robotic (0)
volume group: Offsite-V0
vault name: V0
vault sent date: Mon Jan 21 09:47:51 2008
vault return date: Mon Feb 04 07:52:31 2008
vault slot: 5828
vault session id: 8336
vault container id: -
created: Wed Feb 28 19:50:06 2001
assigned: Mon Jan 21 07:52:30 2008
last mounted: Mon Jan 21 08:56:36 2008
first mount: Wed Feb 28 20:02:24 2001
expiration date: ---
number of mounts: 146
max mounts allowed: ---
status: 0x1
========================================================================
========

Peter J. Horvath III
The Hershey Company
200CA Operations
717-534-6428
phorvath@hersheys.com

Search Discussions

  • Chas. Owens at Jan 29, 2008 at 2:40 pm

    On Jan 29, 2008 9:25 AM, Horvath, Peter wrote:
    Hello Perl guru's,
    I need to pull multiple values form an array. There are
    separator array entries. I need to be able to get all the values between
    the separator values, process them, and then move onto the next group
    till the end. Here is an example of the array.
    snip

    That sure doesn't look like an array, that looks like a file that has
    been read into an array. Reading files into an array is a bad idea
    (reading data multiple times, memory consumption, etc). Try a while
    loop instead:

    #!/usr/bin/perl

    use strict;
    use warnings;

    {
    local $/ = ("=" x 80) . "\n"; #set the record separtor
    while (my $rec = <DATA>) {
    chomp($rec); #remove record separator
    next unless length($rec); #skip empty records
    print "record:\n", map { "\t$_\n" } split /\n/, $rec;
    }
    }

    __DATA__
    ================================================================================
    media ID: 001070
    media type: 1/2" cartridge tape (6)
    barcode: 001070
    media description: V0|256|S190|20040315
    volume pool: NBdatabase (5)
    robot type: NONE - Not Robotic (0)
    volume group: Offsite-V0
    vault name: V0
    vault sent date: Thu Jan 17 21:23:12 2008
    vault return date: Thu Jan 31 19:51:59 2008
    vault slot: 5038
    vault session id: 8314
    vault container id: -
    created: Wed Feb 28 18:55:26 2001
    assigned: Thu Jan 17 19:51:59 2008
    last mounted: Thu Jan 17 20:58:00 2008
    first mount: Wed Feb 28 19:01:24 2001
    expiration date: ---
    number of mounts: 148
    max mounts allowed: ---
    status: 0x1
    ================================================================================
    media ID: 001071
    media type: 1/2" cartridge tape (6)
    barcode: 001071
    media description: V0|432|S3840|00000000
    volume pool: NBdatabase (5)
    robot type: NONE - Not Robotic (0)
    volume group: Offsite-V0
    vault name: V0
    vault sent date: Fri Jan 18 02:35:30 2008
    vault return date: Fri Feb 01 00:01:26 2008
    vault slot: 4884
    vault session id: 8316
    vault container id: -
    created: Wed Feb 28 19:50:06 2001
    assigned: Fri Jan 18 00:01:25 2008
    last mounted: Fri Jan 18 01:23:39 2008
    first mount: Wed Feb 28 20:01:38 2001
    expiration date: ---
    number of mounts: 141
    max mounts allowed: ---
    status: 0x1
    ================================================================================
    media ID: 001072
    media type: 1/2" cartridge tape (6)
    barcode: 001072
    media description: V0|368|S5180|00000000
    volume pool: NBdatabase (5)
    robot type: NONE - Not Robotic (0)
    volume group: Offsite-V0
    vault name: V0
    vault sent date: Mon Jan 21 09:47:51 2008
    vault return date: Mon Feb 04 07:52:31 2008
    vault slot: 5828
    vault session id: 8336
    vault container id: -
    created: Wed Feb 28 19:50:06 2001
    assigned: Mon Jan 21 07:52:30 2008
    last mounted: Mon Jan 21 08:56:36 2008
    first mount: Wed Feb 28 20:02:24 2001
    expiration date: ---
    number of mounts: 146
    max mounts allowed: ---
    status: 0x1
    ================================================================================

    If you really do have an array, your code should look like this
    (warning untested)

    my @lines = however_you_get_the_array_of_lines();
    my @records;
    my $rec;
    for my $line (@lines) {
    if ($line eq ("=" x 80) . "\n") {
    next unless defined $rec; #skip emtpy records
    push @records, $rec;
    $rec = undef;
    next;
    }
    $rec .= $line;
    }
  • Horvath, Peter at Jan 29, 2008 at 3:29 pm
    You are correct. It is a command that I put to an array. I try to work
    with the while loop. Thank you for the guidance.

    -----Original Message-----
    From: Chas. Owens
    Sent: Tuesday, January 29, 2008 9:40 AM
    To: Horvath, Peter
    Cc: beginners@perl.org
    Subject: Re: groups of values from an array
    On Jan 29, 2008 9:25 AM, Horvath, Peter wrote:
    Hello Perl guru's,
    I need to pull multiple values form an array. There are
    separator array entries. I need to be able to get all the values between
    the separator values, process them, and then move onto the next group
    till the end. Here is an example of the array.
    snip

    That sure doesn't look like an array, that looks like a file that has
    been read into an array. Reading files into an array is a bad idea
    (reading data multiple times, memory consumption, etc). Try a while
    loop instead:

    #!/usr/bin/perl

    use strict;
    use warnings;

    {
    local $/ = ("=" x 80) . "\n"; #set the record separtor
    while (my $rec = <DATA>) {
    chomp($rec); #remove record separator
    next unless length($rec); #skip empty records
    print "record:\n", map { "\t$_\n" } split /\n/, $rec;
    }
    }

    __DATA__
    ========================================================================
    ========
    media ID: 001070
    media type: 1/2" cartridge tape (6)
    barcode: 001070
    media description: V0|256|S190|20040315
    volume pool: NBdatabase (5)
    robot type: NONE - Not Robotic (0)
    volume group: Offsite-V0
    vault name: V0
    vault sent date: Thu Jan 17 21:23:12 2008
    vault return date: Thu Jan 31 19:51:59 2008
    vault slot: 5038
    vault session id: 8314
    vault container id: -
    created: Wed Feb 28 18:55:26 2001
    assigned: Thu Jan 17 19:51:59 2008
    last mounted: Thu Jan 17 20:58:00 2008
    first mount: Wed Feb 28 19:01:24 2001
    expiration date: ---
    number of mounts: 148
    max mounts allowed: ---
    status: 0x1
    ========================================================================
    ========
    media ID: 001071
    media type: 1/2" cartridge tape (6)
    barcode: 001071
    media description: V0|432|S3840|00000000
    volume pool: NBdatabase (5)
    robot type: NONE - Not Robotic (0)
    volume group: Offsite-V0
    vault name: V0
    vault sent date: Fri Jan 18 02:35:30 2008
    vault return date: Fri Feb 01 00:01:26 2008
    vault slot: 4884
    vault session id: 8316
    vault container id: -
    created: Wed Feb 28 19:50:06 2001
    assigned: Fri Jan 18 00:01:25 2008
    last mounted: Fri Jan 18 01:23:39 2008
    first mount: Wed Feb 28 20:01:38 2001
    expiration date: ---
    number of mounts: 141
    max mounts allowed: ---
    status: 0x1
    ========================================================================
    ========
    media ID: 001072
    media type: 1/2" cartridge tape (6)
    barcode: 001072
    media description: V0|368|S5180|00000000
    volume pool: NBdatabase (5)
    robot type: NONE - Not Robotic (0)
    volume group: Offsite-V0
    vault name: V0
    vault sent date: Mon Jan 21 09:47:51 2008
    vault return date: Mon Feb 04 07:52:31 2008
    vault slot: 5828
    vault session id: 8336
    vault container id: -
    created: Wed Feb 28 19:50:06 2001
    assigned: Mon Jan 21 07:52:30 2008
    last mounted: Mon Jan 21 08:56:36 2008
    first mount: Wed Feb 28 20:02:24 2001
    expiration date: ---
    number of mounts: 146
    max mounts allowed: ---
    status: 0x1
    ========================================================================
    ========

    If you really do have an array, your code should look like this
    (warning untested)

    my @lines = however_you_get_the_array_of_lines();
    my @records;
    my $rec;
    for my $line (@lines) {
    if ($line eq ("=" x 80) . "\n") {
    next unless defined $rec; #skip emtpy records
    push @records, $rec;
    $rec = undef;
    next;
    }
    $rec .= $line;
    }
  • Chas. Owens at Jan 29, 2008 at 4:04 pm

    On Jan 29, 2008 10:28 AM, Horvath, Peter wrote:
    You are correct. It is a command that I put to an array. I try to work
    with the while loop. Thank you for the guidance.
    snip

    I assume by "a command that I put to an array" you mean you are doing
    something like

    my @lines = `somecommand`;

    To get a file handle for this do

    open my $fh, "-|", "somecommand"
    or die "could not get a file handle for the command somecommand: $!";

    After that point you can use the code I sent you (if you replace DATA
    with $fh). You may also find it useful to access your records as a
    hash like this

    #!/sur/bin/perl

    use strict;
    use warnings;

    open my $fh, "-|", "somecommand"
    or die "could not get a file handle for the command somecommand: $!";

    {
    local $/ = ("=" x 80) . "\n"; #set the record separtor
    while (my $rec = <$fh>) {
    chomp($rec); #remove record separator
    next unless length($rec); #skip empty records
    my %record = map { /(.*?):\s+(.*)/ } split /\n/, $rec;
    print "$record{'media ID'} is in pool $record{'volume pool'}\n"
    }
    }
  • Rob Dixon at Jan 29, 2008 at 4:03 pm

    Horvath, Peter wrote:
    Hello Perl guru's,
    I need to pull multiple values form an array. There are
    separator array entries. I need to be able to get all the values between
    the separator values, process them, and then move onto the next group
    till the end. Here is an example of the array.

    ========================================================================
    ========
    media ID: 001070
    media type: 1/2" cartridge tape (6)
    barcode: 001070
    media description: V0|256|S190|20040315
    volume pool: NBdatabase (5)
    robot type: NONE - Not Robotic (0)
    volume group: Offsite-V0
    vault name: V0
    vault sent date: Thu Jan 17 21:23:12 2008
    vault return date: Thu Jan 31 19:51:59 2008
    vault slot: 5038
    vault session id: 8314
    vault container id: -
    created: Wed Feb 28 18:55:26 2001
    assigned: Thu Jan 17 19:51:59 2008
    last mounted: Thu Jan 17 20:58:00 2008
    first mount: Wed Feb 28 19:01:24 2001
    expiration date: ---
    number of mounts: 148
    max mounts allowed: ---
    status: 0x1
    ========================================================================
    ========
    [snip more data]


    As Chas says, don't put the data into an array in the first place: you
    have gained nothing by importing it into memory. The program below reads
    a file structured like this into an array of hashes, which is likely to
    be the most convenient form for any processing you need to do.

    HTH,

    Rob


    use strict;
    use warnings;

    my @data;
    my %record;

    while (<DATA>) {

    chomp;

    if (/^==/) {
    push @data, {%record} if %record;
    %record = ();
    }
    elsif (/(.+):\s+(.+)/) {
    $record{$1} = $2;
    }
    }
  • Chas. Owens at Jan 29, 2008 at 4:25 pm
    On Jan 29, 2008 11:02 AM, Rob Dixon wrote:
    snip
    if (/^==/) { snip
    elsif (/(.+):\s+(.+)/) {
    Just a few minor quibbles. It is safer to say /^={80}$/ (we don't know
    if == is valid in the field names), you need to limit the greediness
    of the first capture (there might be a : followed by a space in the
    value), you need to be able to match nothing for the field (empty
    values should still show up in the hash), you need to warn the user of
    malformed records, and you need to handle the case where the file does
    not end with the separator.

    use strict;
    use warnings;

    my @data;
    my %record;
    while (<DATA>) {
    chomp;
    if (/^={80}$/) {
    next if keys(%record) == 0; #skip empty records
    push @data, {%record} if %record;
    %record = ();
    } elsif (my ($k, $v) = /(.+?):\s+(.*)/) {
    $record{$k} = $v;
    } else {
    warn "improper record format on line $.\n";
    }
    }
    if (keys %record) {
    push @data, {%record};
    %record = ();
    }

    Of course, I would prefer to read the whole record in and manipulate
    it at once (as I did in my example). Of course, the usage of map
    makes it harder to add the warning, so you might consider doing this
    instead:

    #my %record = map { /(.*?):\s+(.*)/ } split /\n/, $rec;
    my %record;
    for my $line (split /\n/, $rec) {
    my ($k, $v) = $rec =~ /(.+?):\s+(.*)/;
    if (defined $k) {
    $record{$k} = $v
    } else {
    warn "improper record format on line $.\n";
    }
    }
    push @record, \%record;

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupbeginners @
categoriesperl
postedJan 29, '08 at 2:25p
activeJan 29, '08 at 4:25p
posts6
users3
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase