I'm reading Learning Perl (6th edition) and came upon a code snippet that I couldn't decipher. One of the exercises after chapter 14 asks to build a program that takes as input a string and a substring then finds the indices at which the substring occurs in the string.
Here's the way I did it:
print "Enter a string: ";
chomp($string = <STDIN>);
print "Enter a substring: ";
chomp($sub = <STDIN>);
until ($index == -1) {
print $index, "\n" if defined($index);
$index = index($string, $sub, $index + 1);
}
In the answers section, they show two ways. One is easy to understand and similar to mine, but the other is purposefully obfuscating:
print "Enter a string: ";
chomp($string = <STDIN>);
print "Enter a substring: ";
chomp($sub = <STDIN>);
for (my $pos = –1; –1 !=
($pos = index
+$string,
+$sub,
+$pos
+1
);
push #places, ((((+$pos))))) {
'for ($pos != 1; # ;$pos++) {
print "position $pos\n";#;';#' } pop #places;
}
print "Locations of '$sub' in '$string' were: #places\n";
I have almost no idea what's going on in that for loop. I know it's of the form for (initialize; test; increment) and that it's testing that the index is not -1, which means no more occurrences of the substring. But what's going on with the assignment to $pos? Why are there so many parentheses around +$pos? What's going on after the many parentheses? I'd really appreciate it if someone could walk me through the second part. Please keep in mind I've just started learning Perl a week ago.
BTW, I tried running their code but it gave me this error:
Unrecognized character \xE2; marked by <-- HERE after my $pos = <-- HERE near column 16 at ex14.obfs.pl line 1.
I've simplified your example just a little bit, discarded the useless junk and comments. Hope now it is clear what's going on:
print "Please enter a string: ";
chomp(my $string = <STDIN>);
print "Please enter a substring: ";
chomp(my $sub = <STDIN>);
my #places;
for (my $pos = -1; -1 != ($pos = index $string, $sub, $pos+1); push #places, $pos)
{
#do nothing here
}
print "Locations of '$sub' in '$string' were: #places\n";
The compilation error was due to '–' instead of '-';
The inner loop was in fact a string literal (useless) plus comments (useless), the extra braces are useless as well.
Related
I get a weird behavior for chomp. The <STDIN> adds trailing newline to the input, and I want to remove it, so I uses chomp like the following:
print("Enter Your Name:\n");
$n = <STDIN>;
$n = chomp($n);
print("Your Name: $n");
$out = "";
for ($i =0; $i < 10; $i++)
{
$out .= $n;
print ($out);
print("\n");
}
When I enter any name value (string) such as "Fox" I expect output like:
Fox
FoxFox
FoxFoxFox
FoxFoxFoxFox
etc..
However, "Fox" is replaced by numerical value 1 i.e
1
11
111
1111
I tried to get assistance from the official manual of perl about chomp but I could not able to get any help there. Would any one explain why chomp do like that and how could solve this issue?
Edit
I reviewed the example on the book again, I found that they use chomp witout assign i.e:
$n = chomp($n);
# Is replaced by
chomp($n);
And Indeed by this way the script printout as expected! Also I don't know how and why?
From the perldoc on chomp:
It returns the total number of characters removed from all its arguments
You're setting $n to the return value of chomp($n):
$n = chomp($n);
To do what you want, you can simply
chomp($n)
I'm working on a model for predicting disease outcomes and had it working until I started trying to create user prompts. The code stops at the "duration" prompt, located at the bottom of this code block. The script just seems to freeze (blinking cursor) and doesn't go anywhere, but there is 100% processor use so it's doing something. I tried printing text and it seems to stop working at the "duration" prompt. The entire code is on GitHub if you feel like trying to run it yourself.
I've looked it over quite a few times and can't see anything wrong anywhere and am hoping some fresh eyes can see something. I'm sure I made a dumb mistake somewhere. Thanks much!
EDIT: If I remove all the code after "my %population," it works.
#!/usr/bin/perl
use 5.10.1;
#use strict;
use warnings;
use Data::Dumper;
use Storable qw(dclone);
print "Enter number of individuals: ";
my $NUM_IND = <STDIN>;
exit 0 if ($NUM_IND eq "");
print "Enter initial number of infections: ";
my $INIT = <STDIN>;
exit 0 if ($INIT eq "");
print "Enter number contacts per individual: ";
my $CONTACT_RATE = <STDIN>;
exit 0 if ($CONTACT_RATE eq "");
print "Enter disease infectious period: ";
my $INFECTIOUS_PERIOD = <STDIN>;
exit 0 if ($INFECTIOUS_PERIOD eq "");
print "Enter disease virulence: ";
my $INFECTIVITY = <STDIN>;
exit 0 if ($INFECTIVITY eq "");
print "Enter disease incubation period: ";
my $INCUB = <STDIN>;
exit 0 if ($INCUB eq "");
print "Enter number of vaccinations per day: ";
my $VAC = <STDIN>;
print "Enter vaccine efficacy: ";
my $EF = <STDIN>;
print "Enter duration of model: ";
my $DURATION = <STDIN>;
exit 0 if ($DURATION eq "");
print "this works";
my %population = ();
Please never comment out use strict. It is probably worse than not including it in the first place. strict is a huge help with finding bugs in your programs and should be embraced, not avoided.
The reason you are not seeing this works is because the output buffer isn't being flushed. If you add
STDOUT->autoflush;
at the top of your program (say, after the use statements) then it will force the buffer to be flushed after every print statement and you will see your text.
The real problem is this line
for (my $i = 0 ; $i = $INIT ; $i++) {
where your condition is the assignment $i = $INIT which will always be true as long as $INIT is non-zero.
I assume you want $i < $INIT, like the other loops.
But it is far better to use Perl's range operator, which is much clearer to read and isn't vulnerable to mistakes like this. Just use
for my $i (0 .. $INIT-1) { ... }
and it will be obvious what is happening.
I know I'm a newb in Perl so please excuse my stupid mistakes. I am making a calculator that takes user input, but it isn't working. It runs fine and dandy until the if statement, when it reaches the if statement it just ends the program. I looked through forums and books but couldn't find anything.
use warnings;
print "number\n";
$number = <STDIN>;
# Asks the user for what number to calculate.
print "Second number\n";
$secnumber = <STDIN>;
# Asks the user for second number to calculate the first number with
print "Calculation\n Multiplication x\n Addition +\n Substraction -\n ";
$calculation = <STDIN>;
# Asks the user for which calculation to make.
if ($calculation eq "x") {
print "$number" . 'x' . "\n$secnumber" . '=' . "\n" . ($number * $secnumber);
} elsif ($calculation eq "+") {
print "$number" . '+' . "\n$secnumber" . '=' . "\n" . ($number + $secnumber);
} elsif ($calculation eq "-") {
print "$number" . '-' . "\n$secnumber" . '=' . "\n" . ($number - $secnumber);
}
# Displays the calculation and answer.
The value assigned to $calculation will contain a new line character. So on a unix type system the value assigned to $calculation would actually be +\n
you need to use the chomp function which will remove the new line character. you can find more information on chomp with this URL http://perldoc.perl.org/functions/chomp.html
You can apply chomp in two ways. You can have it chomp the new line at the time of reading it
chomp ($calculation = <STDIN>);
Or you can do it after the assignement.
$calculation = <STDIN>;
chomp ($calculation);
Also as a new user to Perl, i would recommend as well as using the warning pragma, you should also use the strict pragma to help you keep good maintainable code.
use warnings;
use strict;
You need to do a chomp($calculation) before the if stmt and after the initial assignment operation. (the $calulation = <STDIN>;).
I have the following small Perl (v5.10) program:
use strict;
my #nums;
my $i = 0;
while ($i < 5) {
print "Enter number " . $i+1 . ": ";
$nums[$i] = <STDIN>;
$i++;
}
foreach (#nums) {
chomp $_;
print "$_\t";
}
print "\n";
This is the result of a test run:
1: 2
1: 1
1: 6
1: 3
1: 2
2 1 6 3 2
The problem, as you can see, is that the print statement prompting the user for input isn't functioning as expected. Instead of "Enter number 1: " or "Enter number 3:", e.t.c., I just get "1:". I didn't expect this to work to be honest because I know that the + operator has been overloaded for string concatenation in Perl. How do I get around this problem? And what is the reason for it?
+ is not overloaded. It is a precedence issue. The expression is parsed as
print(((('Enter number ' . $i) + 1) . ': '));
Which is the same as
print((0 + 1) . ': ');
You can use
perl -MO=Deparse,-p -e 'print "Enter number " . $i+1 . ": ";'
to see how Perl parses your scripts.
Adding parentheses sovles the problem.
Although your immediate problem is incorrect assumption of operator precedence, I see another two (potential) issues that might be interesting as well.
First, it makes little sense using $i + 1, when you can just start your 'output' index from 1, end with 5, but use push to fill the array instead.
Second, it's a bit weird seeing chomp at the output phase of the script, where in fact it should be done in the input phase (as you try to collect numbers from user, don't you?)
For example:
use warnings; use strict;
my #numbers;
for my $i (1..5) {
print "Enter number $i: ";
chomp(my $number = <STDIN>);
push #numbers, $number;
}
print "$_\t" for #numbers;
print "\n";
I have the sequence DNA and I want to find nucleotide of the sequence at the position which was chosed by people. Below is the example:
Enter the sequence DNA:
ACTAAAAATACAAAAATTAGCCAGGCGTGGTGGCAC (the length of sequence is 33)
Enter the position: (12)
I hope the result is the position number 12 the nucleotides are AAA.
I have no problem finding the amino acid of the position. Below is the current code I have.
print "ENTER THE FILENAME OF THE DNA SEQUENCE:= ";
$DNAfilename = <STDIN>;
chomp $DNAfilename;
unless ( open(DNAFILE, $DNAfilename) ) {
print "Cannot open file \"$DNAfilename\"\n\n";
}
#DNA = <DNAFILE>;
close DNAFILE;
$DNA = join( '', #DNA);
print " \nThe original DNA file is:\n$DNA \n";
$DNA =~ s/\s//g;
print" enter the number ";
$po=<STDIN>;
#pos=$DNA;
if ($po>length($DNA))
{
print" no data";
}
else
{
print " #pos\n\n";
}
Please advice how can I find the position at the DNA sequence.
my $nucleotide = substr $DNA, $po, 3;
This will take the 3 nucleotides from positions $po upto $po+2 and assign it to $nucleotide.
That'll be something like this:
use strict;
use warnings;
print 'ENTER THE FILENAME OF THE DNA SEQUENCE:= ';
my $DNA_filename = <STDIN>;
chomp $DNA_filename;
unless (open(DNAFILE, $DNA_filename))
{
die 'Cannot open file "' . $DNA_filename . '"' . "\n\n";
}
my #DNA = <DNAFILE>;
close DNAFILE;
my $DNA_string = join('', #DNA);
print "\n" . 'The original DNA file is:' . "\n" . $DNA_string . "\n";
$DNA_string =~ s/\s//g;
print ' enter the number ';
my $pos = <STDIN>;
if ($pos > length($DNA_string))
{
print ' no data';
}
else
{
print ' ' . substr($DNA_string, $pos, 3) . "\n\n";
}
Some comments:
Always use strict and use warnings - it'll help you to write better and bug-free code.
I personally don't like using interpolation in double quoted strings, hence those concatenations.
Result's position is starting with 0 - if you want, you may change last if's condition and else.
Edit: I've misread part of question about nucleotides, as #hexcoder wrote, you want substr($DNA_string, $pos, 3).