Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Perl file input multiple lines to an array

Status
Not open for further replies.

uscetech

Programmer
Joined
Oct 25, 2006
Messages
7
Location
US
Hey all,

Just wanted to ask a question that's been burning in my head for some time now. Here's an example of a script that I want to modify.

$itemType = "PC";

sub get_item_weight
{
$itemWeight = "";

if ( $itemType eq "PC" ) {
$itemWeight = "50";
}
elsif ( $itemType eq "CPU" ) {
$itemWeight = "10";
}
}

I'm trying to make a script that will edit another script :P Basically I need a front-end that anybody at my work can use, none of them have even heard of perl. I'm trying to make it so they can add to the script from a html form gui. But the problem I'm having is opening the script and imputing certain sections to arrays or strings.

What I need it to do is something allong the lines of opening the file and push everything between "sub get_item_weight {" and the closing sub char "}".

So that array will contain:
$itemWeight = "";

if ( $itemType eq "PC" ) {
$itemWeight = "50";
}
elsif ( $itemType eq "CPU" ) {
$itemWeight = "10";
}

Than I need to go one step further and be able to push everything from "if ... }" or "elsif ... }" to an array or string.

The problem is that I really only know how to input one line at a time. And I want it to grab anything between { and }. Anyone know how to do that? I would greatly appricate it.

Thanks
 
What you need is for users to have data they feed the script, not alter the script itself to try and hardcode the data into the script.

Also, you can't run and edit the same script at the same time if that's what you are trying to do.

The data can be as simple as a text file the main script reads and turns into a data structure the script uses, or a real database that stores the data. But trying to alter the script itself is not a good idea and will most likely just lead to many problems.


- Kevin, perl coder unexceptional!
 
In a nutshell, they will open a script (edit_weights.cgi) that will edit the example script above (get_weights.cgi) and it was save changes to a temp file (edit_weights.cgi.bak) and then once they are done editing, it will rename (edit_weights.cgi.bak) to (edit_weights.cgi) replacing the original.

I don't know how to grep from multiple lines, that the problem. I really, really, dont want to put it all on one line , it will be a mess for me to look at.

So something like:

if ( $itemType eq "PC" ) {
$itemWeight = "50";
$justTesting1 = "1";
$justTesting2 = "2";
}

A shot in the dark:

open (FILE,"< get_weights.cgi");
@arrayWeights=<FILE>;
close FILE;

foreach $line (@arrayWeights) {
$line =~ /{*.*}/
print "$line";
}

Wrong I know but still won't help because it would have to be on the same line. How would I do somthing like that with multiple lines?

So the output would be anything between { and }:
$itemWeight = "50";
$justTesting1 = "1";
$justTesting2 = "2";
 
Just store the data in a file, don't try and hardcode the data into a perl script!

What is the data your users will edit in the code you posted? Is it the values like "50" and "10"?

- Kevin, perl coder unexceptional!
 
Look. Do like Kevin says, put the data in a file, not in the program.
Code:
use strict;
use warnings;
my %weights;

while (<DATA>) {
   chomp;
   my ($item, $weight) = split(/\s+/, $_);
   $weights{$item} = $weight;
}

my $thing = 'PC';
my $thingWeight = $weights{$thing};
print "thing: $thing\tweight: $weight\n"; 

__DATA__
CPU 10
PC 50
veeblefetzer 66
This example has the data file inline with the program, but in reality you'd use a separate file. Which wouldn't contain any perl, if-then-else statements, or anything that your users won't understand.

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
Oops.
Code:
print "thing: $thing\tweight: $[red]thing[/red]Weight\n";
My bad...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
uscetech, you don't seem convinced by Kevin's first post, so I just want to add my voice to his and Steve's. Altering your script this way is a *very* bad idea - there are so many ways it can go horribly wrong. You're far better off storing your data in an extrnal file as they've suggested.
 
Hear, hear. We aren't just picking on you for the sake of it. Programs go wrong even when they are written by competent programmers. IT departments spend a fortune testing code before it goes live, just to prove it works. Allowing non-programmers to modify your code on the fly is a recipe for disaster, particularly if you are the one they call when they screw it up. Keep the code and the reference data separate!

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
It's not that I'm not convinced, just trying to think it all the way through and find the best solution. The _DATA_ solution might work for what I'm doing, but not completely sure. The reason being, there is more to the script than just...

if ( $itemType eq "PC" ) {
$itemWeight = "50";
}
elsif ( $itemType eq "CPU" ) {
$itemWeight = "10";
}

This was just an over simplified example of what I'm trying to do. Here's a more in depth example:

open (FILE,"< inventory_file.txt");
@arrayInventoryFile=<FILE>;
close FILE;

foreach $lineInventory (@arrayInventoryFile) {
($itemNumber, $itemDescription, $itemQuantity, $itemCost, $itemType) = split( /\t/o, $lineInventory );

&get_item_weight;

print "$itemNumber, $itemDescription, $itemQuantity, $itemCost, $itemType, $itemWeight";
}

sub get_item_weight
{
$itemWeight = "";

if ( $itemType eq "PC" ) { #Desktop PC
$itemWeight = "50";
}
elsif ( $itemType eq "CPU" ) { #PC Processor
$itemWeight = "10";
}
elsif ( $itemType eq "MON" ) { #Monitor
if ( $itemDescription =~ /15 inch/i ) {
$itemWeight = "25";
}
elsif ( $itemDescription =~ /17 inch/i ) {
$itemWeight = "35";
}
elsif ( $itemDescription =~ /19 inch/i ) {
$itemWeight = "45";
}
else {
$itemWeight = "UNKNOWN";
}
}
}

The section with $itemType eq "MON" is a better example, there are more items have multiple checks than not. If it where the case that each itemType only had one value, then I could see how Kevin's and Steve's examples would work. Maybe they still can, but I don't know how to implement their suggestion in the "MON" scenario :P

So that another person can hop in and add:
elsif ( $itemDescription =~ /20 inch/i ) {
$itemWeight = "55";
}
And then save it. It's not that I'm stubborn, just getting confused :P

Thanks for the help!
 
Well, that's even worse. I'll have a quick look at it later...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
uscetech,

It's obvious you're confused, I hope that doesn't sound condescending, because it's not meant to. You need a database, pure and simple. We can't say it enough. You're headed for big problems if you continue down your current path. I think we would all prefer not to see you make this mistake.

nuff said.

- Kevin, perl coder unexceptional!
 
Ya tell me about it. Here's the thing, and yes I know how stupid it sounds.

1) They have a database that uses MAS90 for their inventory, but nobody knows how to export the data from it to an excel or csv file. I've tried many things but the limitation is that they don't want me having the user/pass making it impossible to connect to the database using anything.

2) They don't want to take the time to weigh each of the items, so they have me try and hack something together by item type. Except some item types have very different weights.

So basically the only thing I'm able to do is export the inventory to a text file that contains no weights. Then use a perl script to sort the text file and assign weights. It's completely stupid I know, but my hands are tied.

O well, I tried. If I could get a gui that they can use that will basically assign weights to a class/type of items, and maybe per description, I could at leaste get some help going through thousands of items. For now, I have to do it by myself.

Thanks anyhow.
 
It sounds like what you could do is read the file you have:

"export the inventory to a text file"

as each line/entry is read you capture the thing being weighed and assign a weight value to it. Then write that to another file.

Can you post some real sample lines from the text file? And explain them if necessary.



- Kevin, perl coder unexceptional!
 
When it gets exported, it's a text file that looks like:

Item # Description Qty Price Type

0284T Dell Power Supply 2.00 125.00 PWR
02K0849 IBM 3151 Terminal Keyboard 0.00 60.00 KYBD
02K0860 IBM Black Keyboard 1.00 20.00 KYBD
02K3453 IBM SCSI Controller Card 0.00 145.00 DKTP
02K4737 IBM Thinkpad 1400 Keyboard 3.00 95.00 LTPT
02K5060 IBM I Series Keyboard 0.00 50.00 KYBD
540-1823 Sun 88780 Reel Tape Drive 1.00 595.00 TAPE
550S Samsung 15 Inch Monitor 1.00 39.00 MON

Don't know if this helps but...
PWR = Power Supplies
KYBD = Keyboards
DKTP = Desktop Parts
LTPT = Laptop Parts
TAPE = Tape Drives
MON = Monitors
 
OK, that file looks easy enough to munge the data out of. Do you have any idea of how a database file might be formatted so your script (get_weights.cgi?) can use the data? Something like:

Item # Weight
0284T 20
02K0849 10
02K0860 5
02K3453 1
02K4737 8
02K5060 8
540-1823 6
550S 50

- Kevin, perl coder unexceptional!
 
To get a starting database (assuming that item id is unique)
Code:
use strict;
use warnings;

my %weights = (MON => 25, KYBD => 1,
   PWR => 5, DKTP => 1, LTPT => 1, TAPE => 5);

open(DBEXP, "dbExport.txt") or die $!;

while (<DBEXP>) {
   next if ($. == 1);
   my @temp = split(/\s+/, $_);
   my $itemweight = exists $weights{@temp[-1]} ? $weights{@temp[-1]} : 0;
   print "$temp[0] $itemweight\n";
}

close(DBEXP);
This should set the default weight for each item based on its type. Then all you have to do is edit the resulting file of part numbers and weights when you discover that an xyz zz-999 monitor actually weighs 170 kilos rather than 25...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
When you export the inventory from Sage, is it tab-delimited? It's not a CSV, so unless it's got some kind of delimiter, I can't see how you'd import it back in again afterwards.

Assuming tab delimited, then
Code:
use strict;
use warnings;

my %weights = (MON => 25, KYBD => 1,
   PWR => 5, DKTP => 1, LTPT => 1, TAPE => 5);

open(DBEXP, "dbExport.txt") or die $!;
open(DBIMP, ">dbImport.txt") or die $!;

my $cols = <DBEXP>;
chomp $cols;
$cols .= "\tWeight\n";
print DBIMP $cols;

while (<DBEXP>) {
   my @temp = split(/\t/, $_);
   my $itemweight = exists $weights{@temp[-1]} ? $weights{@temp[-1]} : 0;
   print DBIMP "$_\t$itemweight\n";
}

close(DBEXP);
close(DBIMP);
Then open the resulting file in Excel and change the ones that differ wildly from the default.

Once you've got the data back in Sage, make a rule that when you add a new inventory item, you weigh it. This shouldn't be too onerous. So you won't have to do a bulk update again...


Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
Needs a chomp; after the while statement...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
Ok, I'll give these a try. When I export the data from MAS90 it's seperated by spaces only. So the first part of the script which I didn't post just sorts the data into a tab delited txt file (inventory_file.txt). Then I sift the new tab delimited file to get the item to use for retreiving the weight.

Basically the output I want is a tab delimited file containing the previous information plus the weight like:

Item # Description Qty Price Type Weight

0284T Dell Power Supply 2.00 125.00 PWR 15
02K0849 IBM 3151 Terminal Keyboard 0.00 60.00 KYBD 5
02K0860 IBM Black Keyboard 1.00 20.00 KYBD 5
02K3453 IBM SCSI Controller Card 0.00 145.00 DKTP 5
02K4737 IBM Thinkpad 1400 Keyboard 3.00 95.00 LTPT 5
02K5060 IBM I Series Keyboard 0.00 50.00 KYBD 5
540-1823 Sun 88780 Reel Tape Drive 1.00 595.00 TAPE 20
550S Samsung 15 Inch Monitor 1.00 39.00 MON 25

The reason I need to extract this data from the databse is that I need to submit the data to various website's that sell our items, like pricegrabber, froogle, and ebay. Each of these sites has their own format so once it's in a tab delited format, I can sift through it and save it to a file that matches that of the online retailer.

That part I have already done, pricegrabber needs a csv file, froogle needs a txt file, and so on. The only hang up is the weights, everything else is pretty much done.
 
So the problem is you still need to add the weights to the file to produce the above output? Does it still have to be a web based CGI form and script to add the weights? How big is that report file or how many lines is there in the report?

- Kevin, perl coder unexceptional!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top