Perl. How can I make output disappear after several seconds? - perl

I'm prompting a user for a correct answer for example:
/> 13 + 7 ?
is it any way of making this output disappear after 2 seconds for example ?
..thanks' for any suggestions

You're asking for a few things combined, I think:
1) how do you erase a line
2) how do you wait for input for a while and then give up on waiting (ie, a timer)
The following code will do what you want (there are other ways of accomplishing both of the above, but the below shows one way for each of the above tasks):
use strict; use warnings;
use IO::Select;
my $stdin = IO::Select->new();
$stdin->add(\*STDIN);
# always flush
$| = 1;
my $question = "/> 7 + 3 ? ";
print $question;
if ($stdin->can_read(2)) {
print "you entered: " . <STDIN>;
} else {
print "\010" x length($question);
print " " x length($question);
print "too late\n";
}

Use select on STDIN to see whether there is any input within 2 seconds. If not, overwrite the output with a carriage return (\r) or multiple backspaces (\b).
Proof of concept:
$| = 1; # needed because print calls don't always use a newline
$i = int(rand() * 10);
$j = int(rand() * 10);
$k = $i + $j;
print "What is $i + $j ? ";
$rin = '';
vec($rin, fileno(STDIN), 1) = 1;
$n = select $rout=$rin, undef, undef, 2.0;
if ($n) {
$answer = <STDIN>;
if ($answer == $k) {
print "You are right.\n";
} else {
print "You are wrong. $i + $j is $k\n";
}
} else {
print "\b \b" x 15;
print "\n\n";
print "Time's up!\n";
sleep 1;
}
When you are ready for a more advanced solution, you could probably check out Term::ReadKey (so you don't have to hit Enter after you type in your answer) or something like Curses to exercise more control over writing to arbitrary spots on your terminal.

Related

non-numeric argument from user input

In this code the user is asked to input a number from the keyboard. The variable is then used again at a later point in division.
When the code is run it receives a
360/(whatever number was typed) isn't numeric in addition.
Is Perl interpreting the user input as a string instead of a numeric value?
use strict;
use warnings;
use Language::Logo;
print "Enter a number: ";
chomp(my $number = <STDIN>);
my $lo = new Logo(title => "Logo Demonstration");
$lo->command("update 2; color random; pendown; hideturtle");
for ( my $i = 1; $i < 999; $i++ ) {
my $distance = $i / 4;
$lo->command("forward $distance; right 360/$number");
}
$lo->disconnect("Press ctrl+c to exit");
What if you try:
$lo->command("forward $distance; right " . (360/$number));
If that doesn't work, try to force Perl to "see" $number as a number by adding 0 to it:
$rotation = 360 / ($number+0);
$command = "forward $distance; right " . $rotation;
$lo->command($command);
And if that doesn't work either, try to manually set $command to something that DOES work, and report back.

Alignment out of place when done through cgi-perl

I've been trying to implement global alignment algorithm using cgi bioperl. The code works fine and the alignment between the two sequences is perfect using a command prompt. But using cgi the alignment of the two sequences is not perfect. It kinda moves out of place. Here's my code for alignment:
#firstarray = split //, $align1;
#secondarray = split //, $align2;
$sizeoffirst = $#firstarray + 1;
$sizeofsecond = $#secondarray + 1;
print "$sizeoffirst\n"."<br/>";
print "$sizeofsecond\n"."<br/>";
$k = 0;
while ($k <= $sizeoffirst)
{
$count = 1;
$l = $k;
while ($count <= 30)
{
print $firstarray[$l];
$count++;
$l++
}
print "\n"."<br/>";
$count = 1;
$m = $k;
while ($count <= 30)
{
print $secondarray[$m];
$count++;
$m++;
}
print "\n"."<br/>";
print "\n"."<br/>";
$count = 1;
$k = $k + 30;
}
The "dash"(in order to denote a gap) is quite smaller as compare to the letters. Hence the alignment moves out of the place. What can I do?
you should use <pre> so that your formatting is maintained on a web page.
– Barmar
Or a <table>. It's the way to display tabulated data. Also, ALWAYS use strict; use warnings;.
– Toto

input a number and output the Fibonacci number recursively Perl

For a given value N I am trying to output the corresponding Fibonacci number F(N). My script doesn't seem to enter the recursive stage. fibonnaci($number) is not calling the subroutine. It is simply outputing "fibonacci(whatever number is inputted)".
Here is my code:
#!/usr/bin/perl -w
use warnings;
use strict;
print "Please enter value of N: ";
my $number = <STDIN>;
chomp($number);
sub fibonacci
{
my $f;
if ( $number == 0 ) { # base case
$f = 0;
} elsif ( $number == 1 ) {
$f = 1;
} else { # recursive step
$f = fibonacci( $number - 1 ) + fibonacci( $number - 2 );
}
return $f;
}
print "\nf($number) = fibonacci($number)\n";
Sample Output:
Please enter value of N: 4
f(4) = fibonacci(4)
user1:~>recursiveFib.pl
Please enter value of N: 5
f(5) = fibonacci(5)
user1:~>recursiveFib.pl
Please enter value of N: 10
f(10) = fibonacci(10)
user1:~>
Not sure where I went wrong. Any help would be greatly appreciated.
You need to accept the function arguments properly and take the function call out of the quotes.
use warnings;
use strict;
sub fibonacci {
my ($number) = #_;
if ($number < 2) { # base case
return $number;
}
return fibonacci($number-1) + fibonacci($number-2);
}
print "Please enter value of N: ";
my $number = <STDIN>;
chomp($number);
print "\n$number: ", fibonacci($number), "\n";
A more efficient but still recursive version:
sub fib_r {
my ($n,$a,$b) = #_;
if ($n <= 0) { return $a; }
else { return fib_r($n-1, $b, $a+$b); }
}
sub fib { fib_r($_[0], 0, 1); } # pass initial values of a and b
print fib(10), "\n";
Other answers have already mentioned the lack of taking an argument correctly to the fibonacci function, and that you can't interpolate a function call in the print string like that. Lately my favourite way to interpolate function calls into print strings is to use the ${\ ... } notation for embedding arbitrary expressions into strings:
print "f($number) = ${\ fibonacci($number) }\n";
Other techniques include separate arguments:
print "f($number) = ", fibonacci($number), "\n";
or a helper variable:
my $result = fibonacci($number);
print "f($number) = $result\n";
or even printf:
printf "f(%d) = %d\n", $number, fibonacci($number);
Of all these techniques I tend to prefer either of the first two, because they lead to putting the expressions "in-line" with the rest of the text string, whereas in the latter two they sit elsewhere, making it harder to see at a glance what gets printed where. Especially with printf's positional arguments, it can be easy to be "off-by-one" with a large number of arguments, and put everything in the wrong place.
You are printing in wrong way. you just need to handle the return value. Also the way you are using Number in the sub is also not seems relevant. I have updated the and its working fine.
Also the values that you wanted to print is depend on the start up of the series. whether you want to start from 0 or 1.
The series example start with 1 is 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, so if you put 10 you will get 55.
#!/usr/bin/perl -w
use warnings;
use strict;
print "Please enter value of N: ";
my $number = <STDIN>;
chomp($number);
my $result=fibonacci($number);
sub fibonacci
{
my $f =0;
if ($_[0] == 1 ) { # base case
$f = 1;
} elsif ( $_[0] == 2 ) {
$f = 1;
} else { # recursive step
$f= fibonacci( $_[0] - 1 ) + fibonacci( $_[0] - 2 );
}
return $f;
}
print "\nf($number) = $result\n";

Looking for a perl scripts to make addition and pick last number

I am trying to write a simple perl script to learn Perl. This is the first script I have written using user input. The script needs to get a last numbers after make addition function Any help would be appreciated. Below is what I have so far.
Example user input 9423 and then the scripts were make addition function like below
09+04=13
04+02=06
02+03=05
03+09=12
print "Enter 4 Digits Number";#9423
chomp($number = <STDIN>);
EDIT
How to pick a last 2 digits numbers so the results are 3652
#!/usr/bin/perl
my #nums = ("9423" =~ /(\d{1})/g);
my $a = $nums[0];
my $b = $nums[1];
my $c = $nums[2];
my $d = $nums[3];
my $ab= $a+$b;
my $bc= $b+$c;
my $cd= $c+$d;
my $da= $d+$a;
printf "%02d\n%02d\n%02d\n%02d\n", $ab, $bc, $cd, $da;
I think, here code will output your expected result
#!/usr/bin/perl
use warnings;
use strict;
print "Enter 4 Digits Number:";#9423
chomp(my $number = <STDIN>);
my #digits = split("", $number);
my #lasts;
# add first digit to the last position
#digits = 94239
$digits[$#digits + 1] = $digits[0];
for(my $i = 0; $i < $#digits; $i++){
$lasts[$i] = ($digits[$i] + $digits[$i + 1]) % 10;
}
print join "",#lasts,"\n";
output after enter number 9423:
3652
probably easiest way to do it is use a for loop and substring
EDIT (now tested):
for my $i (0 .. length($number)-2) {
print substr($number, $i, 1) + substr($number, $i+1, 1);
}
Perhaps the following will be helpful:
use strict;
use warnings;
print "Enter a 4 Digit Number: ";
chomp( my $num = <STDIN> );
my #nums = split //, $num;
$nums[ $#nums + 1 ] = $nums[0];
( $nums[$_] + $nums[ $_ + 1 ] ) =~ /(.)$/ and print $1 for 0 .. $#nums - 1;
Output after entering 9423:
3652

How do I print a computed score for all input in a file?

Here is some Perl code which takes two files as input. The files contain TCP packets. It trains itself for the normal packets using the packets in first file and then prints the anomalous packets in the second file.
while (<>) {
if (($time, $to, $port, $from, $duration, $flags, $length, $text) = /(.{19}) (.{15}):(\d+) (.{15}):\d+ \+(\d+) (\S+) (\d+) (.*)/) {
$text =~ s/\^M//g;
$text =~ s/\^ /\n/g;
if (($port == 25 || $port == 80) && $text =~ /\n\n/) {$text = "$`\n";}
$text =~ s/^\^#//;
if ($time =~ /(\d\d)\/(\d\d)\/\d\d\d\d (\d\d):(\d\d):(\d\d)/) {
$now = ((($1 * 31 + $2) * 24 + $3) * 60 + $4) * 60 + $5;
}
foreach ($text =~ /.*\n/g) {
if (($k, $v) = /(\S*)(.*)/) {
$k = substr($k, 0, 30);
$v = substr($v, 0, 100);
$score = 0;
$comment = "";
&alarm($port, $k);
&alarm($to, $flags);
&alarm("To", "$to:$port");
&alarm($to, $from);
&alarm("$to:$port", $from);
if ($score > 30000) {
$score = log($score) / (10 * log(10));
printf(" # 0 $time $to %8.6f \#%s\n", $score, substr($comment, 0, 300));
}
}
}
}
}
sub alarm {
local ($key, $val, $sc) = #_;
if ($now < 10300000) {
++$n{$key};
if (++$v{$key . $val} == 1) {
++$r{$key};
$t{$key} = $now;
}
} elsif ($n{$key} > 0 && !$v{$key . $val}) {
$score += ($now - $t{$key}) * $n{$key} / $r{$key};
$comment .= " $key=$val";
$t{$key} = $now;
}
}
exit;
I am new to Perl and as a small part my project it needs that anomaly score is to be printed for all the packets in the second file. Can anybody tell how to modify the code?
From what I can see here, it looks as if the code (as it is now) looks for packets before some cutoff time, and stores whether or not it has seen certain conditions in the %n and %v hashes.
Why not give an extra flag to your alarm function called $training. If true, just account for the packet values, otherwise, calculate a score for this anomaly (if it is one), and return that value. If there is no anomaly, or if you're in training mode, just return zero:
sub alarm {
my ($key, $val, $training) = #_;
my $score = 0;
if ( $training ) {
...do your accounting...
} else {
...do your comparisons & set score accordingly...
}
return $score;
}
Throw your big while into a subroutine, and have that subroutine take a filename and whether it is in training mode or not.
sub examine {
my ($file, $training) = #_;
if ( open my $fh, '<', $file ) {
while (<$fh>) {
...this is your big while loop...
...pass $training along to your alarm() calls...
}
} else {
die "Failed to open $file: $!\n';
}
}
Your main program is now:
use constant TRAINING => 1;
examine('file1', TRAINING);
examine('file2', !TRAINING);
More notes:
Use my() instead of local, though it doesn't materially affect this program, it's a good habit to get into.
Don't use a well known function name alarm when it really isn't doing anything of the kind, instead name it something like check_packet_values -- or something that makes sense to you and your team.
Stop using magic numbers
use constant {
CUTOFF_TIME => 10300000,
ANOMALY_SCORE => 30000
};
Use a real date/time parser so that your values have some meaning. str2time from Date::Parse would give you your time in epoch seconds (seconds since Jan 1, 1970).
Use variable names that mean something. %n and %v are hard to understand in this code, but %n_seen and %value_seen (as well as %first_seen_time instead of %t). Remember, your code doesn't run faster if you use shorter variable names.
Stop using global variables when feasible. The counters can be global, but your comment should be built only in the routine which is initializing and printing the comment. So, instead of doing what you are doing, how about:
$to_score = check_packet_value($to, $flags)
and push #comments, "$to=$flags";
...
$score = $to_score + $from_score + ...
if ( !$training && $score > ANOMALY_THRESHOLD ) {
print "blah blah blah #comments\n";
}
Also, never, ever use $` -- it causes huge performance penalties in your entire script (even if it never calls this function). Instead of:
if ( $text =~ /\n\n/ ) { $text = $` }
Use
if ( $text =~ /(.*)\n\n/ ) {
$text = $1;
}
(Edit: added warning about $`)
I may have misunderstood your question and comment, so forgive me if this isn't what you're asking...
Your printf function currently resides inside this if ($score > 30000) check, so you'll only get the output if the $score is > 30000.
if ($score>30000) {
$score=log($score)/(10*log(10));
printf(" # 0 $time $to %8.6f \#%s\n", $score, substr($comment, 0, 300));
}
If you want to print the output regardless of the $score, you just need to move the printf line outside this if check.