Perl script not running conditional statements? - perl

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>;).

Related

Splitting and printing with Perl

My Perl script is attempting to take in a command line argument that is a file name such as name.txt or hello.txt.exe and parse out the file extension based on the . delimiter, and print only the extension like exe or txt. Here's what I currently have which doesn't print anything and I'm not entirely sure why.
usr/bin/perl -w
use strict;
my ($user_arg) = shift #ARGV;
my ($ext);
if ( ($ext) = $user_arg =~ /(\.[^.].+)$/)
{
print "Ends in ", ($ext) = $user_arg =~ /(\.[^.].+)$/ , "\n";
print "Ends in" , ($ext) = $user_arg =~ /(\.[^.]+)$/, "\n";
}
elsif( ($ext) = $user_arg =~ /(\.[^.]+)$/)
{
print"Ends in " , ($ext), "\n";
}
else
{
print "No Extension";
}
*Updated, now my problem is the first statement will print both conditions if it's something like name.txt it will print .txt twice, where I want it to only print .txt once UNLESS it's name.txt.exe where I'd like it to print .txt.exe then .exe
There's two main issues here:
1) You need to shift off #ARGV
my $arg = shift #ARGV;
2) You need to escape the 'dot'
my #values = split /\./, $user_arg;
Other things...
You usually want to sanitize user input:
die "usage: $0 filename\n" if {some condition}
I think you mean chomp $val; in your foreach.
It wouldn't hurt to be familiar with File::Basename, fileparse could make your life easier. Although it might be overkill here.
UPDATE
You should be able to integrate this yourself. In your case you won't need to loop
over a list of files, you'll just have one.
This doesn't do what you want where it prints "txt.exe", "exe". But you can fine tune this to your liking.
my #file_tests = qw(nosuffix testfile.txt /path/to/file.exe foo.bar.baz);
for my $fullname (#file_tests) {
my #names = split /\./, $fullname;
# shift off the first element, which will
# give you the list of suffixs or an empty list
shift #names;
# you can decide how you want to print this list
# if scalar #names is 0 don't print anything
print "list of suffixes: " . join( ', ', #names ) . "\n"
if scalar(#names) > 0;
}
OUTPUT:
list of suffixes: txt
list of suffixes: exe
list of suffixes: bar, baz

simple perl addition program going wrong?

Hi i am a novice perl learner this simple perl program
$inputline= <STDIN>;
print "first input";
print( $inputline);
$inputline=<STDIN>;
print "second input";
print($inputline);
$sum= $inputline+$inputline;
print"sum 1stinput and 2ndinput";
print($sum);
output
perl count.pl
3
4
first input3
second input4
sum 1stinput and 2ndinput : 8
why is the output 8 instead of being 7?
Because you add $inputline to itself when it is 4.
If you want to sum the two inputs, you either have to do it with two variables, or do the addition before the variable changes. E.g.:
my $input1 = <>;
my $input2 = <>;
my $sum = $input1 + $input2;
print "Sum: $sum";
Or
my $input = <>;
my $sum = $input;
$input = <>;
$sum += $input;
print "Sum: $sum";
You could do something simpler, such as:
perl -nlwe '$sum += $_; print "Sum: $sum";'
Which is basically the equivalent of:
use strict;
use warnings; # always use these
my $sum;
while (<>) { # your input
$sum += $_;
print "Sum: $sum\n";
}
Use Ctrl-C or Ctrl-D to break out of the loop (Ctrl-Z in windows).
You're using the variable $intputline twice. The second time you refer to it, it overwrites the previous value. You need to use unique variable names for each variable:
$inputline1= <STDIN>;
print "first input";
print( $inputline1);
$inputline2=<STDIN>;
print "second input";
print($inputline2);
$sum= $inputline1+$inputline2;
print"sum 1stinput and 2ndinput";
print($sum);
How can Perl (or anyone else) distinguish $inputline from $inputline? Choose a different name for the second variable.
Always and without fail include the following pragmas at the top of your scripts:
use strict;
use warnings;
Use lexically-scoped variables ("my"):
my $inputline= <STDIN>;
print "first input";
print( $inputline);
my $inputline=<STDIN>;
...
Running this would raise the following exception:
"my" variable $inputline masks earlier declaration in same scope at ...
Using these pragmas and "my" can help you to avoid this and many other potentially problematic areas in your scripts.
Hope this helps!

In Perl, how to use plus operator for arithmetic calculation in print statement?

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";

Perl Dynamically Generated Multidimentional Associative Array

This may be a simple oversight on my part (or something much more advanced than my skill set). I am trying to dynamically fill a 2d associative array by reading input from a file.
my #data;
while (<FILE>) {
chomp;
my $ID,$COUNT;
print "READ: " . $_ . "\n"; #Debug 1
($ID,$COUNT,undef,undef,undef) = split /\,/;
print "DATA: " . $ID . "," . $COUNT . "\n"; # Debug 2
$data{$ID}{"count"} = $COUNT;
#push #{$data{$ID}{"count"}}, $COUNT;
print $data{$ID}{"count"} . "\n"; # Debug 3
}
The first print (Debug 1) will print a line similar to des313,3,,,.
The second print (Debug 2) will print a line DATA: des313,3
The third print (Debug 3) will print a blank line.
The issue seems to be in the way I am trying to insert the data into the associative array. I have tried both the direct insert and the push method with no results. I have done this with PHP however I think I am overlooking this in Perl. I did look at the perldoc perldsc page in the section of HASHES of HASHES however I did not see it talk about dynamic generation of them. Any suggestions would be great!
Assigning to the hash the way you have should work fine. You are declaring your variables improperly. Your associative array is called a hash in Perl, and is prefixed with a % sigil, so you should write my %data before the while loop. Inside the loop, the my operator needs parens to apply to a list, so it should be my ($ID, $COUNT);.
This minimal example works properly:
use warnings; # place these lines at the top of all of your programs
use strict; # they will catch many errors for you
my %data; # hash variable
while (<DATA>) {
chomp;
my ($id, $count) = split /,/; # simplify the split
$data{$id}{count} = $count; # build your hash
}
print "got: $data{des313}{count}\n"; # prints "got: 3"
__DATA__
des313,3

Find nucleotides in DNA sequence with perl

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).