phizymonk has asked for the wisdom of the Perl Monks concerning the following question:

Below is the question I need help on what I have is a program that reads the file prints what is read but I need a way to change what was read and then save it to the file that I opened. The exact wording of the problem is below. I also posted my attempt and work so far I am pretty stuck at the moment.

"write a Perl program that will allow the user to read some data from a file, and then give the user the option of modifying the price of an item, and then store the information back to a file that can be read again later. "

open(FH, "gp1data.txt") || die("Cannot open the file."); print "$_"; while (<FH>){ print "$_"; } my %menu; while (my $line2 = <$prices>) { chomp $line2; my @row = split(/-/, $line2); $menu{$row[0]} = $row[1]; }

The text file says Hamburger - 1.79 Cheeseburger - 2.00 Fries - 1.50

I need to be able to add or change the number of items and prices but I need to store them into a hash after reading the file.

Replies are listed 'Best First'.
Re: Hashes and Associative Arrays
by GrandFather (Saint) on Jan 27, 2016 at 02:50 UTC

    It would help us if you show us what the content of the file looks like. For test purposes it's really handy to have the test data "built in" (see I know what I mean. Why don't you? for hints on doing that).

    A couple of, not quite related, tips will help with finding and fixing problems generally:

    • Always use strictures (use strict; use warnings;)
    • Always use three parameter open and lexical file handles (open my $fh, '<', $filePath or die "Can't open '$filePath': $!\n")

    It helps a lot while developing code to ignore unimportant stuff like managing input and output files. The "built in data" trick isn't just for us, it helps you too. Perl helps by letting you tack an input file to the end of the script with __DATA__ and you can use print without a file handle to see the output immediately in the console without having to dig into an output file.

    Without worrying about how to write the code, how did you imagine a user of the script would give the edit information? From the user's perspective what do you imagine the sequence of events to be?

    Premature optimization is the root of all job security

      I am updating it now and I will post here aswell with the new code. The text file says this exactly Hamburger - 1.79 Cheeseburger - 2.00 Fries - 1.50

      I took a different approach and had perl read the file print what it said then take that and put it into a hash now I need to take user input and change the hash. My guess would be to use a foreach loop to run through each line of the uploaded hash and change it.

      use strict; use warnings; my $file = 'gp1data.txt'; open my $info, $file || die "Could not open $file: $!"; while( my $line = <$info>) { chomp($line); print $line; (my $word1, my $word2) = split /-/, $line; $hash{word1} = $word2; } while ( my ($k, $v) = each $hash){ print "key $k => $v\n"; } <>;

        You haven't yet taken your programmer hat off and put a user hat on. Until you do that and specify how the user will interact with your script, you can't write the script!

        Is your input really all on one line? Maybe you need to put your sample data in code tags (you can edit your node to do that).

        Premature optimization is the root of all job security
Re: Hashes and Associative Arrays -- modify an array given user input
by Discipulus (Canon) on Jan 27, 2016 at 12:18 UTC
    hello phizymonk, welcome to the monastery and to the wonderful world of Perl

    following the path GrandFather drawn for you (think about the program before coding) and as you are learning Perl i propose you some pseudo-code insetead of a a full featured script that satisfy your task. I add some sparse suggestion that you can try to expand to code. GrandFather insisted on specifications: how the user will interact with the program? it is important! Generally speaking if you are able to write in plain language the solution, then you'll be able to code it or at least (if your skill are not enought) to spot what part you are not able to code: it is a great advantage.

    As foreword suggestions, try to code in a plain and well documented way, idiomatically: as already said by GrandFather use strict and warnings, use open with 3 arguments (idiomatic = more reliable and less error prone). Try to isolate behaviours in subroutines: it will help a lot when the code become more complex. And, very important, choose meaningfull names for your variables.

    I think you simply need an array instead of an hash: you definetively read an array of lines from file. Work with this array; it is indexed, it is easy to use and faster and without side effects (duplicate can exists in a file and in array not in an hash)

    # pseudocode # PART 0 - load useful stuffs and define some useful vars use strict; use warnings; # maybe use Term::ReadLine; # a useful tool to grab user input my $filename = $ARGV[0] || 'defaultfile.txt'; my $separator = ' - '; # in your OP you split using '-' and this leave +s a blank space after the item an another before the price! my $was_modified = 0; # count total modifications make a copy of the original file with a date in the name and possibly +another exstension, just in case open the file for reading my @alllines = <$file_handle>; # in list context <> reads all the line +s (good for not huge files) # ATTENTION: you still have all newline +s at end of each record!! close file_handle or die # PART 1 - present the file to the user: show also the index of the ar +ray that we will use to modify the entry, later # better to define a sub to show the file content: sub showfile { foreach my $index( 0 .. $#alllines ) { # $#alllines is the last ind +ex (the number of) of the @alllines array chomp $alllines[$index]; # remove newlines print "[$index] $alllines[$index]\n" } modify_from_input; # call teh sub defined below: grab user input and +come back to this sub again } showfile; # call the sub # PART 2 - edit prices # grab the user input and modify the array entry. a sub is better sub modify_from_input { print "Enter the index you want to modify: (0 - $#alllines)\n"; my $input = ... # grab the input chomp $input; # remember newlines! if input is invalid warn something and call the same sub again else my ($name, $price) split $separator, $alllines[$index]; print "Enter new price for [$name] (was [$price]) or 'write' to writ +e the file:\n" my $new_price = <STDIN>; chomp $new_price; # validate $new_price ? if new_price is empty -> remove the item? -> splice the array -> sho +wfile return if $new_price eq 'write'; # break the loop of the 2 subs and +go to the end of program # modification! $was_modified++; $alllines[$index] = $name.$separator.$new_price; showfile; # we go back in show mode } # PART 3 - modify the file: we arrive here only if user enter 'write' +while in the modify_from_input sub open my $write, '>', filename or die # here we are rewriting the orig +inal file print $write "$_\n" for @alllines; if $was_modified print "$was_modified modifications were applied\n" else print "no modifications\n" close $write or die; print "$filename succesfully written\n"; exit 0;


    have fun filling the blanks!

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.