On Wed, Jun 20, 2001 at 11:41:29PM +0100, Mark Bedish wrote:
> I am using substrings in a screipt and wondered if there was a better
> perlish way to do it. I am taking data from a mainframe system and
> reformatting it but the substring seems to be quite slow, like visual
> basic, the original.
> 
> Any pointers on a better method would be much appreciated.

I can't really give any pointers on a better method because I don't know
enough about what you're doing in order to generalize things.  However,
substr shouldn't, by any means, be slow, unless you're doing a lot of
operations, in which case anything you do is likely to be slow.

However, there are some optimizations, both speed and readability-wise, that
can be done with your code examples.


 
> my @fields = unpack($template, $_);

What is $template, anyhow?



> # add zoned decimals - overpunch requires translation
> for $i (8,9,10,12)  {

This seems very odd.  Perhaps you should just unpack what you need, using
the "@" template.

 
>     if (unpack(c1,(substr($fields[$i],-1))) > 57)
>     {
> 
>         substr($fields[$i],-1) =~ tr/}JKLMNOPQR/0123456789/;
>         $fields[$i] = '-' . substr($fields[$i],1,12);
>     }
>     
>     # add decimal, point
>     $fields[$i] = substr($fields[$i],0,11) . '.' .
> substr($fields[$i],-2);
> }


Probably better written as:

    foreach my $field (@fields[8, 9, 10, 12]) {
        if (ord(substr($field, -1)) > 57) {
            substr($field, -1) =~ tr/}JKLMNOPQR/0123456789/;
            substr($field, 0, 1) = "-";
        }

        # add decimal point
        substr($field, 11, 0) = ".";
    }

I hope I've got the gist of it, but even if not, you can adapt the ideas.

I'm assuming each of your fields is a 13-character string you're turning
into a number.  Regarding the decimal, you could also divide by 100, though
you may run into floating point overflows.


 
> # find bad character and replace with a space or whatever
> my @testbad = unpack(c65,$fields[7]);
> 
> print LOG "Unpacked format for array: \n";
> 
> for $i (0..64)  { print LOG $testbad[$i]; }

    print LOG join("", @testbad);

This is assuming you're not running with -l.


> print LOG "\n";
> 
> for $i (0..64)  {
> 
>     if ($testbad[$i] == 13) { $testbad[$i] = 40; }
>     
>         
>     }

    foreach my $bad (@testbad) {
        if ($bad == 13) { $bad = 40 }
    }

or, better yet, replace the unpack and this loop with:

    $fields[7] =~ tr/\x0D/\x20/;


You'll notice here, and above in the fields processing, I'm using the
aliasing feature of foreach.  $bad (and above, $field) are aliases of each
element of the array, so modifications carry through.


I have no idea if this'll help you, but there you go.


Michael
--
Administrator                      www.shoebox.net
Programmer, System Administrator   www.gallanttech.com
--

Reply via email to