Noob! Help required and would be really appreciated!

H

Henry Law

I'm really getting confused as to whats happening here!

I don't blame you. Just retire to a corner while it blows over. And
remember not everyone who posts in this group is like you (i.e.
rational, polite and just wanting to find out how to write their code ...)

The posting guidelines are shorthand for doing some very sensible
things, which I'd summarise as

(1) Write code and then ask why what you've written isn't doing what you
expected. Why is that in the guidelines? Because discussing code
that's written and is in front of us all is lots easier and more precise
than code that exists only in people's heads.

(2) Distil your problem down into its essence, eliminating as far as
possible all the things that don't pertain to the bit you can't get
right. Why? Because people will be able to see much more easily where
your problem is, and be able to help you more quickly, if the stuff that
works and isn't relevant isn't there.

(3) If possible (and it isn't always) create a program that will run on
anyone's machine, so they can copy and paste it into their own editor,
save and run it. Why? Because that way they can experiment a bit
with it if they need to. Also because if there's something wrong with
your Perl installation the code will give different results (maybe
correct ones) for the person who's trying to help you and that will
flush out the problem with your system.

The guidelines /may/ have been worked out by a tiny group of people (I
suspect not) but - believe me - they are eminently good sense and
following them will help you enormously.
 
J

jl_post

I know this is a lot to ask for, I've read 60% of learning perl
and i kinda know what i should do (pattern matching?) but
am quite lost. Any help would be appreciated

Dear Deepak,

You've read 60% of "Learning Perl"? Excellent! Be sure and read
the rest (and don't forget to do the excercises!).

As for your task at hand, let's see if I can help you out.
My pseudo code is this

Firstly the given file has to be scanned row by row.

On finding the keyword "New Order", it has to start building a hash.

Let us say that the program encounters the first "New Order".

It has to then build a hash and the value of the key is the value of
the parameter - orderid


Okay, you've specified that he will build a hash whenver we
encounter the key words "New Order". So far so good. Obviously, we
want to build a loop around this hash creation. We'll call the hash we
want to populate "%order", since it keeps track of one order.

Before we go any farther, here are some thoughts:

1. Because we will have several loops (one for each line of input and
one for each order), it will really help us out to "use strict" and
"use warnings". Some people think they're not necessary because "they
can code well enough without it" and theoretically they might be
correct. However, using "strict" forces us to declare our variables,
and believe it or not, that will make the task easier, as every time we
declare a variable it is guaranteed not to be populated with a previous
value. Not using "strict" will make the task more difficult, as you
will be forced to clear out variables at the proper time. Forget to do
that, and you will have many hard-to-find bugs in your code.

Also, it's good programming practice to always "use strict" and "use
warnings". Those two lines alone find up to an estimated 90% of all
beginner (and advanced) Perl bugs. If they're so useful, why not use
them? They can literally save you hours of debugging time. (So please
use them. Always.)

2. Let's take a shortcut: instead of manually open()ing your input
file (and checking for errors), let's read from <> (the diamond
operator -- I'm pretty sure it's mentioned in "Learning Perl"). This
operator reads from an input file automatically, whenter you specify it
as an argument to your Perl script, pipe it in with "|", or redirect it
to your script with "<" at the command prompt. It's an extremely
useful little thing that even will Do The Right Thing and tell you if
it can't open the input file!

3. As I mentioned before, we'll have two loops: an inner loop that
loops line-by-line that breaks out whenever it has a full record/order.
The outer loop is a quasi-infinite loop that loop through your entire
input. In other words, the inner loop loops through all the lines of
an order (but only one!), whereas the outer loop loops through all the
orders, one by one.

4. The structure that contains the data for all the orders will be
named "%allOrders". The structure that contains the data for just one
order will be named "%order". Hopefully you will understand that at
some point during the outer loop the data in %order will somehow be
transferred to %allOrders.

5. Looking at your sample data, I notice that there are two separate
lines that specify the userOrdrNum. Is this a mistake, or do you
really have to handle two userOrdrNum lines per order? It won't matter
much if the lines are identical, but if the values differ, you'll have
to figure out yourself how you want them to be handled.

Let me show you the kind of Perl script I would write. I'll
intermix real Perl code and pseudo-code, and let you do the task of
adding the real Perl code to the pseudo-code:


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

# Declare the hash that will hold all the info
# for all the orders:

my %allOrders;

# Loop until there are no more lines of input:

until (eof())
{
# Declare the hash that will hold all the info
# for just one order:

my %order;

while (<>)
{
# We'll break out of this loop if we find
# line that contains "New Order". However,
# the first time we encounter this line is
# an exception, because there was no
# previous order to process. Therefore,
# We'll only break out of the loop if
# "New Order" is found and %order is
# not empty:

last if m/New Order/ and %order;

chomp; # remove the newline

# We might have a blank line or something, so check
# to make sure that we have a valid line. You might
# use something like this:

next unless m/:/; # skip line if it doesn't contain a colon

# If we get here, then we know we have a line like:
# userOrdrNum: 123456tttter
# or:
# ordrRmngQty: +000000000400

# Let's split() the line out into key/value pairs:

my ($key, $value) = # put proper split() code here

# Now that we have the key/value pair,
# let's insert into our %order hash:

$order{$key} = $value;
}

# If we get here, then we know that we either
# have a full order (because we broke out with
# the "last if m/New Order/" line) or have just
# run out of input (in which case we should have
# a full order anyway).

# In either case, our full order is in the %order
# hash, and we need to get it into the %allOrders
# hash. But what should we use as the key?

# You said yourself that you wanted to use the
# userOrdrNum as the key. So first, let's check
# to see if it exists in the %order hash. If it
# doesn't, we'll print an informative warning message
# and loop to the next record:

unless ( # check to see if "userOrdrNum" exists in %order )
{
warn "WARNING! Order found with no userOrdrNum!\n";
next; # loop to begin processing next record
}

# If we get here, then we know we have an %order with
# a userOrdrNum. Let's extract the uderOrdrNum:

my $userOrderNumber = $order{uderOrdrNum};

# Now here comes the fun part: We transfer the
# %order hash to the %allOrders hash. The
# $userOrderNumber will be the key while the
# %order itself is the value:

$allOrders{$userOrderNumber} = \%order;

# Now we're all done with this order. We'll just
# loop to the next order/record, until we run out
# of lines of input!
}

# Once we get here, we have finished processing
# all the input and we can query the %allOrders
# hash like this:

if (exists($allOrders{123456tttter})
{
print "Order 123456tttter exists!\n";

if (exists($allOrders{123456tttter}{cntrExerPrc})
{
print "Its cntrExerPrc is: ",
$allOrders{123456tttter}{cntrExerPrc},
"\n";
}

}
else
{
warn "Order 123456tttter doesn't exist!\n";
}

# You can even print out all the data in
# %allOrders like this:

print "Printing all the data in %allOrders:\n";

use Data::Dumper; # this is a standard module (you already have it)
print Dumper \%allOrders;

__END__


Once you have this script fully written, you should be able to run
it with any of the following lines at your prompt:

perl script.pl input.txt
perl script.pl < input.txt
cat input.txt | perl script.pl

(Of course, this assumes that you named your Perl script "script.pl"
and your input file as "input.txt".)


So that's it. The only really tricky part of this script is the
line:

$allOrders{$userOrderNumber} = \%order;

Since hash keys must always be scalars (and never hashes or arrays), we
can't assign the %order hash directly to the %allOrders hash. Instead,
we'll assign a "reference" of the %order hash to the %allOrders array
by putting a back-slash in front of %order (make sure it's a backslash
and not the more common frontslash). This reference is a scalar
itself, making it suitable to be a value for a hash.

In case you don't know by now, the %allOrders hash is actually a
"hash of hashes." If I remember correctly, "Learning Perl" doesn't
cover hash of hashes, but the perldocs do. To read more about them,
just type:

perldoc perldsc

at your command prompt. (You may also want to read about arrays of
arrays, which you can by typing "perldoc perllol".)

Well, that's pretty much it. Just convert the pseudo-code in the
above program and you'll have a working program that populates the
%allOrders hash with your data. How you query your data and what you
do with it is up to you.

(Note that the above program might seem huge, but take heart: If
you actually count up the lines of code, you'll find that there are
less than a dozen that actually populate the %order and %allOrders
hashes.)

I hope this helps, Deepak.

-- Jean-Luc Romano
 
A

Anno Siegel

(e-mail address removed) wrote:

[elaborate explanation snipped]
So that's it. The only really tricky part of this script is the
line:

$allOrders{$userOrderNumber} = \%order;

Since hash keys must always be scalars (and never hashes or arrays), we
^^^^
You mean hash *values* here. Keys are even more restricted and must be
strings.
can't assign the %order hash directly to the %allOrders hash. Instead,
we'll assign a "reference" of the %order hash to the %allOrders array
by putting a back-slash in front of %order (make sure it's a backslash
and not the more common frontslash). This reference is a scalar
itself, making it suitable to be a value for a hash.

Another bit is a little tricky with this assignment. It is essential
that the code correctly makes the hash %order a lexical variable in the
body of the outer loop, so that a refreshing "my %order" is run each time
through. That way, the assignment at the end of the loop assigns a new
and different hash to each $userOrderNumber. If the declaration were
outside the scope of the loop, as in declaring all your variables near
the beginning of the program, the reference stored in each loop would be
the same, with unpleasant results.

Anno
 

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

Forum statistics

Threads
474,008
Messages
2,570,268
Members
46,867
Latest member
Lonny Petersen

Latest Threads

Top