What is the right way to stop an infinite while-loop with a Term::Readline-readline? - perl

What is the right way to stop an endless while-loop with a Term::Readline::readline?
This way I can not read in a single 0
#!/usr/bin/env perl
use warnings;
use strict;
use 5.010;
use Term::ReadLine;
my $term = Term::ReadLine->new( 'Text' );
my $content;
while ( 1 ) {
my $con = $term->readline( 'input: ' );
last if not $con;
$content .= "$con\n";
}
say $content;
and with
last if not defined $con;
the loop does never end.

You can do it the way it is shown in the documentation:
use strict; use warnings;
use Term::ReadLine;
my $term = Term::ReadLine->new('Text');
my $content = '';
while ( defined (my $con = $term->readline('input: ')) ) {
last unless length $con;
$content .= "$con\n";
}
print "You entered:\n$content\n";
Output:
C:\Temp> t
input: one
input: two
input:^D
You entered:
one
two

Related

Parsing a GenBank file

I trying to parse a GenBank file so I could get the accession number, the definition, the size of the file and the DNA sequence
Is there a way to modify my code and make it shorter and just declare all the variables at once like they do in the book and parse the file in one or two blocks of code?
If you have access to Bio Perl, you might find a solution such as the following.
#!/usr/bin/perl
use strict;
use warnings;
use Bio::SeqIO;
my $in = Bio::SeqIO->new( -file => "input.txt",
-format => 'GenBank');
while ( my $seq = $in->next_seq ) {
my $acc = $seq->accession;
my $length = $seq->length;
my $definition = $seq->desc;
my $type = $seq->molecule;
my $organism = $seq->species->binomial;
if ($type eq 'mRNA' &&
$organism =~ /homo sapiens/i &&
$acc =~ /[A-Za-z]{2}_[0-9]{6,}/ )
{
print "$acc | $definition | $length\n";
print $seq->seq, "\n";
print "\n";
}
}
I was able to capture the 5 variables from a sample GenBank file I have (input.txt). It should simplify your code.

How to substitute " with " in perl

I want to substitute all " in the string $input with /" and I come up with the following code:
#!/usr/bin/perl -w
use CGI;
use CGI::Carp qw ( warningsToBrowser fatalsToBrowser );
my $q = CGI -> new;
print $q -> header();
$input = 'abc"abc';
(my $output = $input) =~ s/"/"/g;
print "input = $input\n";
print "output = $output\n";
However, the $output is not changed. How can I get this right?
You should use a module suitable for the purpose, such as HTML::Entities:
use strict;
use warnings;
use HTML::Entities;
my $input = 'abc"abc';
print encode_entities($input);
Output:
abc"abc
In your code, the variable $input is not changed because you are using parentheses to avoid it.
(my $output = $input) =~ s/"/"/g;
This will enforce the assignment to happen first, overruling precedence. Then the regex substitution is applied to $output. When I run your code, I get the expected output:
input = abc"abc
output = abc"abc
If you do not get this output, I expect the quotes in your string is something different than you think.

how to compare the the array values with different file in different directory?

#!/usr/bin/perl
use strict;
use warnings;
use warnings;
use 5.010;
my #names = ("RD", "HD", "MP");
my $flag = 0;
my $filename = 'Sample.txt';
if (open(my $fh, '<', $filename))
{
while (my $row = <$fh>)
{
foreach my $i (0 .. $#names)
{
if( scalar $row =~ / \G (.*?) ($names[$i]) /xg )
{
$flag=1;
}
}
}
if( $flag ==1)
{
say $filename;
}
$flag=0;
}
here i read the content from one file and compare with array values, if file contant matches with array value i just display the file. in the same way how can i access different file from different direcory and compare the array values with same?
Q: How can I access a different file?
A: By specifying a different filename.
By the way: If you are using flags for loop control in Perl, you are doing something wrong. You can specify that this was the last iteration of the loop (in C: break), or that you want to start the next iteration. You can label the loops so that you can break out of as many loops as you like at once:
#!/usr/bin/perl
use 5.010; use warnings;
my #names = qw(RD HD MP);
# unpack command line arguments
my ($filename) = #ARGV;
open my $fh, "<", $filename or die "Oh noes, $filename is bad: $!";
LINE:
while (my $line = <$fh>) {
NAME:
foreach my $name (#names) {
if ($line =~ /\Q$name\E/) { # \QUOT\E the $name to escape everything
say "$filename contains $name";
last LINE;
}
}
}
Other highlights:
using a foreach loop as intended and
removing the (in this context) senseless \G assertion
You can then execute the script as perl script.pl Sample.txt or perl script.pl ../another.dir/foo.bar or whatever.
You can use the ~~ operator in Perl 5.10.
Don't forget to chomp the trailing whitespace.
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my #names = ('RD', 'HD', 'MP');
my $other_dir = '/tmp';
my $filename = 'Sample.txt';
if ( open( my $fh, '<', "$other_dir/$filename" ) ) {
ROW:
while ( my $row = <$fh> ) {
chomp $row; # remove trailing \n
if ( $row ~~ #names ) {
say $filename;
last ROW;
}
}
}
close $fh;

Printing specific line from a hash in perl

My question is how can I print a specific line from a hash. The code so far(Thank you Joel Berger for it) is:
#!/usr/bin/env perl
use strict;
use warnings;
use LWP::Simple;
my $content = get('http://temptrax.itworks.com/temp');
my %probes = $content =~ /Probe\s*(\d)\|\s*(\-?[\d\.]+)/gx;
foreach my $probe (sort keys %probes) {
print "$probe => $probes{$probe}\n";
}
The output of it is:
1 => 74.0
2 => -99.9
3 => 74.4
4 => 68.1
How can I get a specific line to print? Such as if I put in number 1, then only line 1 would print. Thank you for taking a look at this.
UPDATE: I was finally able to figure it out after some reading
#!/usr/bin/env perl
use v5.10.1;
use strict;
use warnings;
use LWP::Simple;
my $content = get('http://temptrax.itworks.com/temp');
my %probes = $content =~ /Probe\s*(\d)\|\s*(\-?[\d\.]+)/gx;
for ($ARGV[0]) {
when(1) {print "$probes{1}\n"; }
when(2) {print "$probes{2}\n"; }
when(3) {print "$probes{3}\n"; }
when(4) {print "$probes{4}\n"; }
default {print "error"; }
}
UPDATE2: Figured out an even easier way to do it
#!/usr/bin/env perl
use v5.10.1;
use warnings;
use LWP::Simple;
my $content = get('http://temptrax.itworks.com/temp');
my %probes = $content =~ /Probe\s*(\d)\|\s*(\-?[\d\.]+)/gx;
$MyVar = $ARGV[0];
print $probes{$MyVar};
print $probes{1};
Perhaps? Rather simple. Or:
print "$_ => ", $probes{$_} for 1,2,4; # selected numbers

Split and add digits

If I open a file with strings like "233445", how can I then split that string into digits "2 3 3 4 4 5" and add each one to each other "2 + 3 + 3 etc..." and print out the result.
My code so far looks like this:
use strict;
#open (FILE, '<', shift);
#my #strings = <FILE>;
#strings = qw(12243434, 345, 676744); ## or a contents of a file
foreach my $numbers (#strings) {
my #done = split(undef, $numbers);
print "#done\n";
}
But I don't know where to start for the actual add function.
use strict;
use warnings;
my #strings = qw( 12243434 345 676744 );
for my $string (#strings) {
my $sum;
$sum += $_ for split(//, $string);
print "$sum\n";
}
or
use strict;
use warnings;
use List::Util qw( sum );
my #strings = qw( 12243434 345 676744 );
for my $string (#strings) {
my $sum = sum split(//, $string);
print "$sum\n";
}
PS — Always use use strict; use warnings;. It would have detected your misuse of commas in qw, and it would have dected your misuse of undef for split's first argument.
use strict;
my #done;
#open (FILE, '<', shift);
#my #strings = <FILE>;
my #strings = qw(12243434, 345, 676744); ## or a contents of a file
foreach my $numbers (#strings) {
#done = split(undef, $numbers);
print "#done\n";
}
my $tot;
map { $tot += $_} #done;
print $tot, "\n";
No one suggested an eval solution?
my #strings = qw( 12243434 345 676744 );
foreach my $string (#strings) {
my $sum = eval join '+',split //, $string;
print "$sum\n";
}
If your numbers are in a file, a one-liner might be nice:
perl -lnwe 'my $sum; s/(\d)/$sum += $1/eg; print $sum' numbers.txt
Since addition only uses numbers, it is safe to ignore all other characters. So just extract them one at the time with the regex and sum them up.
TIMTOWTDI:
perl -MList::Util=sum -lnwe 'print sum(/\d/g);' numbers.txt
perl -lnwe 'my $a; $a+=$_ for /\d/g; print $a' numbers.txt
Options:
-l auto-chomp input and add newline to print
-n implicit while(<>) loop around program -- open the file name given as argument and read each line into $_.