[comp.lang.perl] source code

frech@mwraaa.army.mil (Norman R. Frech CPLS) (06/06/90)

Greetings,

I am fairly new to perl and the following is a program which I
developed to read a file off an ibm and convert the packed values
to something usable.  It then writes the data down in delimited form
for dbaseiii.  The program seems to work but I have a feeling
it is a terrible hack and would appreciate some kind criticism
or possible improvements, etc.

Thanks, Norm Frech <frech@mwraaa.army.mil>

*** cut here ***
@lookup[0] = ('{}0');
@lookup[1] = ('AJ1');
@lookup[2] = ('BK2');
@lookup[3] = ('CL3');
@lookup[4] = ('DM4');
@lookup[5] = ('EN5');
@lookup[6] = ('FO6');
@lookup[7] = ('GP7');
@lookup[8] = ('HQ8');
@lookup[9] = ('IR9');
while (<>) {
chop;
$field1 = substr($_,0,5);
$field2 = substr($_,5,13);
$field3 = substr($_,18,4);
$field4 = substr($_,22,40);
$field5 = substr($_,62,1);
$field6 = substr($_,63,1);
$field7 = substr($_,64,3);
$onhand = substr($_,67,9);
$stock_val = substr($_,76,9);
$field8 = substr($_,85,9);
$field9 = substr($_,94,1);
$field10 = substr($_,95,5);
# ship two values to be whack
$onhand = &packibm($onhand);
$stock_val = &packibm($stock_val);
# print the values
print "\"",$field1,"\"\,\"",$field2,"\"\,\"",$field3,"\"\,\"";
print $field4,"\"\,\"",$field5,"\"\,\"",$field6,"\"\,\"",$field7;
print "\"\,",$onhand,"\,",$stock_val,"\,",$field8;
print "\,\"",$field9,"\"\,\"",$field10,"\"\n";
}
sub packibm {
local($value) = @_;
$len = length($value);
$tend = substr($value,0,$len - 1);
$lval = substr($value,$len - 1,1);
$get = &calval($lval);
if ($i < 10) {
return($tend * 10 + $i);
}
else
{
return($tend * 10 * -1 + (($i - 10) * -1));
}
}
sub calval {
for ($i = 0; $i < 10; $i++) {
for ($j = 0; $j < 3; $j++) {
$look = substr(@lookup[$i],$j,1);
if ($lval =~ $look) { 
if ($j == 1) {
$i = $i + 10;
}
return $i;
}
}
}
}
*** cut here ***

merlyn@iwarp.intel.com (Randal Schwartz) (06/06/90)

In article <1990Jun6.004442.14479@uvaarpa.Virginia.EDU>, frech@mwraaa (Norman R. Frech CPLS) writes:
| Greetings,
| 
| I am fairly new to perl and the following is a program which I
| developed to read a file off an ibm and convert the packed values
| to something usable.  It then writes the data down in delimited form
| for dbaseiii.  The program seems to work but I have a feeling
| it is a terrible hack and would appreciate some kind criticism
| or possible improvements, etc.

Here's what I could do in 15 minutes.  Might be a few typos.  Caveat
Executor.

I tried to keep your logic and order (had to, with that time limit),
but part of the work is learning to "Think Perl".

################################################## cut here
@lookup = split(/ /,'{}0 AJ1 BK2 CL3 DM4 EN5 FO6 GP7 HQ8 IR9');

while (<>) {
	chop;
	($f1,$f2,$f3,$f4,$f5,$f6,$f7,$onhand,$stock_val,$f8,$f9,$f10) =
	/^(.{5})(.{13})(....)(.{40})(.)(.)(...)(.{9})(.{9})(.)(.{5})/;
	# ship two values to be whack
	$onhand = &packibm($onhand);
	$stock_val = &packibm($stock_val);
	# print the values
	print '"', join('","', $f1, $f2, $f3, $f4, $f5, $f6, $f7,
		$onhand, $stock_val, $f8, $f9, $f10), '"', "\n";
}

sub packibm {
	local($_) = @_;
	local($tend,$lval) = /(.*)(.)/;
	local($get) = &calval($lval);
	if ($get < 10) { ## meant $get instead of $i, I hope
		return($tend * 10 + $get);  ## ditto
	} else {
		return($tend * 10 * -1 + (($get - 10) * -1));  ## ditto
	}
}

## there is something very non-perlish about the following code, but
## I couldn't reverse engineer it in the few minutes I had to do this.
## Larry?

sub calval {
	local($i,$j);
	for ($i = 0; $i < 10; $i++) {
		for ($j = 0; $j < 3; $j++) {
			$look = substr(@lookup[$i],$j,1);
			if ($lval =~ $look) { 
				if ($j == 1) {
					$i = $i + 10;
				}
				return $i;
			}
		}
	}
}
################################################## cut here

print substr("Of course, I'm Just another Perl hacker,",-25,25);
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (06/07/90)

In article <1990Jun6.022140.13168@iwarp.intel.com> merlyn@iwarp.intel.com (Randal Schwartz) writes:
: In article <1990Jun6.004442.14479@uvaarpa.Virginia.EDU>, frech@mwraaa (Norman R. Frech CPLS) writes:
: | Greetings,
: | 
: | I am fairly new to perl and the following is a program which I
: | developed to read a file off an ibm and convert the packed values
: | to something usable.  It then writes the data down in delimited form
: | for dbaseiii.  The program seems to work but I have a feeling
: | it is a terrible hack and would appreciate some kind criticism
: | or possible improvements, etc.
: 
: Here's what I could do in 15 minutes.  Might be a few typos.  Caveat
: Executor.
: 
: I tried to keep your logic and order (had to, with that time limit),
: but part of the work is learning to "Think Perl".
: 
: ################################################## cut here
: @lookup = split(/ /,'{}0 AJ1 BK2 CL3 DM4 EN5 FO6 GP7 HQ8 IR9');

@code{ '{', 'A' .. 'I', '}', 'J' .. 'R', '0' .. '9' } = (0 .. 19, 0 .. 9);
 
 or

for (split(//, "{ABCDEFGHI}JKLMNOPQR0123456789")) { $code{$_} = $cnt++ % 20; }

 or even

%code = (
	'{',	0,	'}',	10,	'0',	0,
	'A',	1,	'J',	11,	'1',	1,
	'B',	2,	'K',	12,	'2',	2,
	'C',	3,	'L',	13,	'3',	3,
	'D',	4,	'M',	14,	'4',	4,
	'E',	5,	'N',	15,	'5',	5,
	'F',	6,	'O',	16,	'6',	6,
	'G',	7,	'P',	17,	'7',	7,
	'H',	8,	'Q',	18,	'8',	8,
	'I',	9,	'R',	19,	'9',	9,
};

: while (<>) {
: 	chop;
: 	($f1,$f2,$f3,$f4,$f5,$f6,$f7,$onhand,$stock_val,$f8,$f9,$f10) =
: 	/^(.{5})(.{13})(....)(.{40})(.)(.)(...)(.{9})(.{9})(.)(.{5})/;

more efficiently:

	unpack("c5 c13 c4 c40 c c c3 c9 c9 c c5", $_);

: 	# ship two values to be whack
: 	$onhand = &packibm($onhand);
: 	$stock_val = &packibm($stock_val);
: 	# print the values
: 	print '"', join('","', $f1, $f2, $f3, $f4, $f5, $f6, $f7,
: 		$onhand, $stock_val, $f8, $f9, $f10), '"', "\n";

I presume we don't need to check for embedded '"'?

: }
: 
: sub packibm {
: 	local($_) = @_;
: 	local($tend,$lval) = /(.*)(.)/;
: 	local($get) = &calval($lval);

local($tend) = @_;
local($get) = $code{ chop($tend) };

: 	if ($get < 10) { ## meant $get instead of $i, I hope
: 		return($tend * 10 + $get);  ## ditto
: 	} else {
: 		return($tend * 10 * -1 + (($get - 10) * -1));  ## ditto
: 	}
: }
: 
: ## there is something very non-perlish about the following code, but
: ## I couldn't reverse engineer it in the few minutes I had to do this.
: ## Larry?
: 
: sub calval {
: 	local($i,$j);
: 	for ($i = 0; $i < 10; $i++) {
: 		for ($j = 0; $j < 3; $j++) {
: 			$look = substr(@lookup[$i],$j,1);
: 			if ($lval =~ $look) { 
: 				if ($j == 1) {
: 					$i = $i + 10;
: 				}
: 				return $i;
: 			}
: 		}
: 	}
: }

This whole subroutine can be replaced by a single associative array lookup.
See $code{} above.

Actually, now that I glare at the whole thing, you can do packibm like this

    sub packibm {
	local($_) = @_;
	if (tr/}J-R/0-9/) {
	    $_ = -$_;
	}
	else {
	    tr/{A-I/0-9/;
	}
	$_;
    }

Larry

markb@agora.uucp (Mark Biggar) (06/10/90)

In article <1990Jun6.022140.13168@iwarp.intel.com> merlyn@iwarp.intel.com (Randal Schwartz) writes:
>	($f1,$f2,$f3,$f4,$f5,$f6,$f7,$onhand,$stock_val,$f8,$f9,$f10) =
>	/^(.{5})(.{13})(....)(.{40})(.)(.)(...)(.{9})(.{9})(.)(.{5})/;

It is much more efficient to do this with unpack like so:

    ($f1,$f2,$f3,$f4,$f5,$f7,$onhand,$stock_val,$f8,$f9,$f10) =
	unpack('a5a13a4a40a1a1a3a9a9a1a5', $_);

Two enhancements to unpack would make things like this easier: 1) allow the
	second argument to default to $_ and 2) if there is anything left over
	after unpacking it should be returned as the last item in the list.

Mark Biggar