Unpack - getting values directly into the correct variables

P

PugetSoundSylvia

Hello all,

I'm just starting to get into perl, so please forgive me if I'm asking
something obvious.

I'm using the unpack function to parse through a fixed length file.
It's working well, but there's lots and lots of fields, and I'd like
to make the code more readable.

What I have now is this:

$LOGFILE = "text.log";
open(LOGFILE) or die("Could not open log file.");

# Define the record format for unpack function
$BaseBSPFileTemplate =
"A3" # RecordType Field 0
."A8" # SequenceNumber Field 1
."A2" # RecordTypeSuffix Field 2
."A6" # CreateDate Field 3
."A6" # TransactionNumber Field 4
."A15" # DataNumber Field 5
."A98" # UpdateDate Field 6
;

while (<LOGFILE>) {

@fields = unpack( $BaseBSPFileTemplate, $_ );

$RecordType = $fields[0];
$SequenceNumber = $fields[1];
$RecordTypeSuffix = $fields[2];

... and so forth ...

Is there a better way to do this - one where the unpack function
itself would automatically split it into the actual variables
($RecordType, $SequenceNumber, $RecordTypeSuffix, etc) - instead of me
having to have the section that has a bunch of rows like this:

$RecordType = $fields[0];

Thanks much for any advice!!

Sylvia
 
X

xhoster

while (<LOGFILE>) {

@fields = unpack( $BaseBSPFileTemplate, $_ );

$RecordType = $fields[0];
$SequenceNumber = $fields[1];
$RecordTypeSuffix = $fields[2];

... and so forth ...

Is there a better way to do this - one where the unpack function
itself would automatically split it into the actual variables
($RecordType, $SequenceNumber, $RecordTypeSuffix, etc) - instead of me
having to have the section that has a bunch of rows like this:

You can assign directly to a list of variables:

my ( $RecordType,
$SequenceNumber,
$RecordTypeSuffix,
# ....
) = unpack( $BaseBSPFileTemplate, $_ );


Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
J

John W. Krahn

I'm just starting to get into perl, so please forgive me if I'm asking
something obvious.

I'm using the unpack function to parse through a fixed length file.
It's working well, but there's lots and lots of fields, and I'd like
to make the code more readable.

I see that Xho has answered your unpack question but ...
What I have now is this:

You should really have these two lines at the beginning of your program:

use warnings;
use strict;
$LOGFILE = "text.log";

Which means that you have to declare this variable:

my $LOGFILE = 'text.log';
open(LOGFILE) or die("Could not open log file.");

And you should really be using the three argument form of open(). As
well, you should include the $! variable in the error message so you
know why it failed:

open LOGFILE, '<', $LOGFILE or die "Could not open '$LOGFILE' $!";



John
 
A

A. Sinan Unur

(e-mail address removed) wrote in
@t12g2000prg.googlegroups.co
m:
Hello all,

I'm just starting to get into perl, so please forgive me if I'm
asking something obvious.

I'm using the unpack function to parse through a fixed length
file. It's working well, but there's lots and lots of fields, and
I'd like to make the code more readable.

What I have now is this:

$LOGFILE = "text.log";
open(LOGFILE) or die("Could not open log file.");

# Define the record format for unpack function
$BaseBSPFileTemplate =
"A3" # RecordType Field 0
."A8" # SequenceNumber Field 1
."A2" # RecordTypeSuffix Field 2
."A6" # CreateDate Field 3
."A6" # TransactionNumber Field 4
."A15" # DataNumber Field 5
."A98" # UpdateDate Field 6
;

while (<LOGFILE>) {

@fields = unpack( $BaseBSPFileTemplate, $_ );

$RecordType = $fields[0];
$SequenceNumber = $fields[1];
$RecordTypeSuffix = $fields[2];

#!/usr/bin/perl

use strict;
use warnings;

my @fields = qw( RecordType SequenceNumber RecordTypeSuffix
CreateDate TransactionNumber DataNumber UpdateDate );

my %formats;
@formats{ @fields } = qw( A3 A8 A2 A6 A6 A15 A98 );

my $unpack_tmpl = join( '', @formats{ @fields } );

while( <DATA> ) {
last if /^\s+$/;
my %obs;
@obs{ @fields } = unpack $unpack_tmpl;

print "$_\t$obs{$_}\n" for @fields;

}

__END__
00011111111223333334444445555555555555556666666666666666666666666666
66666666666666666666666666666666666666666666666666666666666666666666
66


--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
J

John W. Krahn

A. Sinan Unur said:
(e-mail address removed) wrote in
@t12g2000prg.googlegroups.co
m:
Hello all,

I'm just starting to get into perl, so please forgive me if I'm
asking something obvious.

I'm using the unpack function to parse through a fixed length
file. It's working well, but there's lots and lots of fields, and
I'd like to make the code more readable.

What I have now is this:

$LOGFILE = "text.log";
open(LOGFILE) or die("Could not open log file.");

# Define the record format for unpack function
$BaseBSPFileTemplate =
"A3" # RecordType Field 0
."A8" # SequenceNumber Field 1
."A2" # RecordTypeSuffix Field 2
."A6" # CreateDate Field 3
."A6" # TransactionNumber Field 4
."A15" # DataNumber Field 5
."A98" # UpdateDate Field 6
;

while (<LOGFILE>) {

@fields = unpack( $BaseBSPFileTemplate, $_ );

$RecordType = $fields[0];
$SequenceNumber = $fields[1];
$RecordTypeSuffix = $fields[2];

#!/usr/bin/perl

use strict;
use warnings;

my @fields = qw( RecordType SequenceNumber RecordTypeSuffix
CreateDate TransactionNumber DataNumber UpdateDate );

my %formats;
@formats{ @fields } = qw( A3 A8 A2 A6 A6 A15 A98 );

my $unpack_tmpl = join( '', @formats{ @fields } );

while( <DATA> ) {
last if /^\s+$/;
my %obs;
@obs{ @fields } = unpack $unpack_tmpl;

Don't forget the variable that you want to unpack:

@obs{ @fields } = unpack $unpack_tmpl, $_;

print "$_\t$obs{$_}\n" for @fields;

}

__END__
00011111111223333334444445555555555555556666666666666666666666666666
66666666666666666666666666666666666666666666666666666666666666666666
66


John
 
A

A. Sinan Unur

A. Sinan Unur wrote: ....


Don't forget the variable that you want to unpack:

@obs{ @fields } = unpack $unpack_tmpl, $_;

I didn't ;-) From perldoc -f unpack:

unpack TEMPLATE,EXPR
unpack TEMPLATE
....
If EXPR is omitted, unpacks the $_ string.

Sinan

--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to

$BaseBSPFileTemplate =
"A3" # RecordType Field 0
."A8" # SequenceNumber Field 1
."A2" # RecordTypeSuffix Field 2
."A6" # CreateDate Field 3
."A6" # TransactionNumber Field 4
."A15" # DataNumber Field 5
."A98" # UpdateDate Field 6
;

while (<LOGFILE>) {

@fields = unpack( $BaseBSPFileTemplate, $_ );

$RecordType = $fields[0];
$SequenceNumber = $fields[1];
$RecordTypeSuffix = $fields[2];

What a horror... Here is an example (Audio::FindChunks):

my $wav_header = <<EOH;
a4 # header: 'RIFF'
V # size: Size of what follows
a4 # type: 'WAVE'

a4 # type1: 'fmt ' subchunk
V # size1: Size of the rest of subchunk
v # format: 1 for pcm
v # channels: 2 stereo 1 mono
V # frequency
V # bytes_per_sec
v # bytes_per_sample
v # bits_per_sample_channel

a4 # type2: 'data' subchunk
V # sizedata: Size of the rest of subchunk
EOH

my @wav_fields = ($wav_header =~ /^\s*\w+\s*#\s*(\w+)/mg);

$wav_header =~ s/#.*//g; # For v5.005
....
@vals{@wav_fields} = unpack $wav_header, $in or ...

Hope this helps,
Ilya
 
J

John W. Krahn

A. Sinan Unur said:
I didn't ;-) From perldoc -f unpack:

unpack TEMPLATE,EXPR
unpack TEMPLATE
...
If EXPR is omitted, unpacks the $_ string.

That must be new for 5.10 cause it doesn't work in 5.8.8

$ perl -le'
$_ = q[1234567890123456789012345678901234567890];
print for unpack q[a4 a7 a3];
'
Not enough arguments for unpack at -e line 3, near "q[a4 a7 a3];"
Execution of -e aborted due to compilation errors.



John
 
P

Peter J. Holzer

$BaseBSPFileTemplate =
"A3" # RecordType Field 0
."A8" # SequenceNumber Field 1
."A2" # RecordTypeSuffix Field 2
."A6" # CreateDate Field 3
."A6" # TransactionNumber Field 4
."A15" # DataNumber Field 5
."A98" # UpdateDate Field 6
;

while (<LOGFILE>) {

@fields = unpack( $BaseBSPFileTemplate, $_ );

$RecordType = $fields[0];
$SequenceNumber = $fields[1];
$RecordTypeSuffix = $fields[2];

What a horror...

You could have phrased that more politely :).

Actually, I think that's pretty low on the horror-scale. Tedious and
redundant, yes, but I've seen much worse code.
Here is an example (Audio::FindChunks):

my $wav_header = <<EOH;
a4 # header: 'RIFF'
V # size: Size of what follows
a4 # type: 'WAVE'

a4 # type1: 'fmt ' subchunk
V # size1: Size of the rest of subchunk
v # format: 1 for pcm
v # channels: 2 stereo 1 mono
V # frequency
V # bytes_per_sec
v # bytes_per_sample
v # bits_per_sample_channel

a4 # type2: 'data' subchunk
V # sizedata: Size of the rest of subchunk
EOH

my @wav_fields = ($wav_header =~ /^\s*\w+\s*#\s*(\w+)/mg);

$wav_header =~ s/#.*//g; # For v5.005
...
@vals{@wav_fields} = unpack $wav_header, $in or ...

Clever. Maybe a bit too clever for production code. At least I would add
a comment about the format (so that the next maintainer doesn't break
it) and why it works.

I'd use an array of arrays instead:

#!/usr/bin/perl
use warnings;
use strict;


my @BaseBSPFileFormat = (
["RecordType", "A3" ],
["SequenceNumber", "A8" ],
["RecordTypeSuffix", "A2" ],
["CreateDate", "A6" ],
["TransactionNumber", "A6" ],
["DataNumber", "A15" ],
["UpdateDate", "A98" ],
);
my $BaseBSPFileTemplate = join('', map $_->[1], @BaseBSPFileFormat);
my @BaseBSPFileFields = map $_->[0], @BaseBSPFileFormat;

while (<DATA>) {

my %fields;
@fields{@BaseBSPFileFields} = unpack( $BaseBSPFileTemplate, $_ );

for (@BaseBSPFileFields) {
print "$_: $fields{$_}\n";
}
print "\n"
}
__DATA__
111222222223344444455555566666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
111222222223344444455555566666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777

hp
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top