LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   New to Perl, and its acting funny (https://www.linuxquestions.org/questions/programming-9/new-to-perl-and-its-acting-funny-759078/)

SuperDude123 10-01-2009 04:51 PM

New to Perl, and its acting funny
 
Here's my code:
-------------------------
#!/usr/bin/perl

open (IN, "in.txt");
open (OUT, ">out.txt");
my $search1 = 'cup_cakes_sold = ';

while (<IN>){
$found = (index($_, $search1));
if ($found){
$sep = (index($_, ""));
$temp = (substr($_, $sep));
print OUT $temp."4";
}
else{
print OUT $_;
}
}
close IN;
close OUT;
-------------------------



Here's my in.txt file

-------------------------
pancakes = 4



cup_cakes_sold = 3
-------------------------

Here's my out.txt file

-------------------------
pancakes = 4
5
5
5
5cup_cakes_sold = 3
-------------------------

Now what I was trying to do was have out.txt be the same as before, but have my script change the cup_cakes_sold = 3 to cup_cakes_sold = 4. Can someone spot the mistake? This is my first perl script.

waltuotinen 10-01-2009 05:51 PM

Perl acting funny
 
Perl rarely acts "funny", but it can drive you nuts.

Here are a few tips that may help you get things going the way you want:

$found = (index($_, $search1));
if ($found){ ...

Your conditional logic will execute everytime EXCEPT when the in.txt record contains "cupcakes sold =", because the "index" function returns the offset of the beginning of the string you're looking for in a zero-based fashion. If it's found at the first character, index returns 0 (which is Boolean false). If index doesn't find the string, it returns -1, which is Boolean true.

$sep = (index($_, ""));

This line of code will always assign 0 to $sep, since your asking index to find a null string, which occurs everywhere, hence the first occurence is 0.

Assuming that you just want to change the number of cupcakes from whatever it is to 4, consider this substituting this code instead of all that index and substring stuff:

s/(cup_cakes_sold =).*$/\1 4/;

Also, if you haven't already, buy these 2 O'Reilly books:
Learning Perl
Programming Perl

Best regards,
Walt Uotinen
a.k.a. "The Perl Guy" around my office

gzunk 10-01-2009 05:56 PM

I'm not entirely sure what you're trying to do, but your first problem is that the perl function index doesn't return "false" when it doesn't find the value. Therefore your test always succeeds.

The second problem is that you then search for the empty string, which it finds straight away at position 0 (which is correct, the empty string is always the first substring that you can get in a string)

Then you get the subset of the string starting from position 0 (the offset that you've just found) which returns the entire string, then you print that out, appending a "4" at the end. So I would expect your output to look like this:

Code:

pancakes = 4
4
4
4
4cup_cakes_sold = 3

Do you want to add one to the cupcakes, or just change it to 4?

smeezekitty 10-01-2009 06:00 PM

Quote:

Originally Posted by waltuotinen (Post 3704263)
Best regards,
Walt Uotinen
a.k.a. "The Perl Guy" around my office

would look better with a :)
for example
modfied quote:
"
Best regards,
Walt Uotinen
a.k.a. "The Perl Guy" around my office :)
"

SuperDude123 10-01-2009 06:27 PM

I want to change cup_cakes_sold = 3 to cup_cakes_sold = 4 without all the 4's everywhere. How do I do that?

ghostdog74 10-01-2009 07:30 PM

Quote:

Originally Posted by SuperDude123 (Post 3704319)
I want to change cup_cakes_sold = 3 to cup_cakes_sold = 4 without all the 4's everywhere. How do I do that?

here's a pseudocode,try coding yourself:
Code:

if ( found cup_cakes_sold ) {
  split string on "=" #hint : split() function
  change last element of array returned by split to 4
  join string back together # hint: join()
}


smeezekitty 10-01-2009 07:31 PM

Quote:

Originally Posted by ghostdog74 (Post 3704377)
here's a pseudocode,try coding yourself:
Code:

if ( found cup_cakes_sold ) {
  split string on "=" #hint : split() function
  change last element of array returned by split to 4
  join string back together # hint: join()
}


i remember you
you dont just give somebody the code
you will put a trick in it and they figure it out

gregorian 10-01-2009 10:44 PM

Quote:

Originally Posted by SuperDude123 (Post 3704319)
I want to change cup_cakes_sold = 3 to cup_cakes_sold = 4 without all the 4's everywhere. How do I do that?

I hope you're saying that after reading the above posts.

SuperDude123 10-01-2009 10:51 PM

Yes, now I have a vague understanding of what I need to do, I just don't know how to do it.

What I want to do is count how many characters there are all the way up to the = sign in the sentence cup_cakes_sold = [some number], and then I need to print those x characters, then tell perl to print " 4" afterwards to do the effect of what I want.

Now if it doesn't see that line in that string of code (correct term??), it is to print it and move on. Could someone tell me what and where I've done wrong with my true/false thing? I realize that its doing the -1 code, however, can someone provide either a solution or a working example so I can see how its supposed to work?

Sergei Steshenko 10-01-2009 10:58 PM

One begins with Perl putting

Code:

use strict;
use warnings;

in the beginning of his/her script.

SuperDude123 10-01-2009 11:02 PM

That just resulted in the following erros:

Global symbol "$found" requires explicit package name at perltest.txt line 17.
Global symbol "$found" requires explicit package name at perltest.txt line 18.
Global symbol "$sep" requires explicit package name at perltest.txt line 19.
Global symbol "$temp" requires explicit package name at perltest.txt line 20.
Global symbol "$sep" requires explicit package name at perltest.txt line 20.
Global symbol "$temp" requires explicit package name at perltest.txt line 21.
Execution of perltest.txt aborted due to compilation errors.

chrism01 10-02-2009 12:56 AM

You'll find these useful:
http://perldoc.perl.org/
http://www.perlmonks.org/?node=Tutorials

Also, if you have access to those links, I recommend the Perl Cookbook over Programming Perl.


Your 1st task is to sort those issues caused by adding

use strict;
use warnings;

I highly recommend you use those cmds in ALL your Perl progs, even the short temp throwaway ones. They'll save you so much grief in the long run.

gzunk 10-02-2009 06:58 AM

Here's a solution, based on waltuotinen's suggestion

Code:

use strict;
use warnings;

open (IN, "in.txt");
open (OUT, ">out.txt");

while (<IN>){
        s/(cup_cakes_sold =).*$/$1 4/;
        print OUT $_;
}

close IN;
close OUT;

The first bit, use strict and use warnings, tells perl that you must defined all variables before using them, and it should flag warnings. This is best practice since it stops you from becoming lazy.

The next two lines open the file descriptors. The while loop goes through the input file line by line.

The we have the magic. We use perl's regular expression handling to perform a substitution on the input line. This basically says, find a line that contains "cup_cakes_sold =" and has multiple things after the equals sign. and substitute it with cup_cakes_sold= 4.

The brackets in the regular expression allow us to save what is matched in the brackets and refer to it as $1. the "." in the regular expression means match any character. The * in the regular expression means match zero or more of the preceding character) in this case ".". the $ means match the end of the line.

waltuotinen 10-02-2009 08:02 AM

Perl acting funny
 
Try this code:

#!/usr/bin/perl
open (IN, "in.txt");
open (OUT, ">out.txt");
my $search1 = 'cup_cakes_sold = ';
while (<IN>){
if (/(cup_cakes_sold = )(\d+)/) {
$newNum = $2 + 1;
s/(cup_cakes_sold =).*/\1 $newNum/;
}
print OUT $_;
}
close IN;
close OUT;

It will identify any record read in from in.txt that contains
"cup_cakes_sold = " followed by one or more digits, then it will
add 1 to the digit(s) value, and replace the string "cup_cakes_sold = "
with the same string followed by the newly incremented number (i.e., 3 becomes 4, 27 becomes 28, etc.).

Walt

gregorian 10-02-2009 08:56 PM

To the OP: I understand you're more interested in understanding what went wrong in your program rather than receiving suggestions for improvement. I've worked on the the suggestions given by waltuotinen (Post #2) and I've changed other things as well. Here's your corrected program with the minimal changes.

Code:

#!/usr/bin/perl

open (IN, "in.txt");
open (OUT, ">out.txt");
my $search1 = 'cup_cakes_sold = ';

while (<IN>){
        $found = index($_, $search1);
        if ($found >= 0){
                $sep = index($_, $search1);
                $temp = substr($_, $sep, length($search1));
                print OUT $temp."4";
        }
        else{
                print OUT $_;
        }
}
close IN;
close OUT;

"print" is your best friend as a new learner. If you're satisfied with this, I suggest you read this thread from the beginning as there's a much simpler way to do this.

perldoc -f <functionname> is the also very useful.


All times are GMT -5. The time now is 10:40 PM.