How do I accept a list of integers as input? The only thing I can think of is getting each integer from the list specifically using STDIN. Is there a better way to do this?
You want input a list of integers? I take it you mean that you want to enter a list of numbers, and accept that input if they're all integers.
In this program, I loop forever until I get a valid list, thus for (;;). Some people prefer while (1).
I use Scalar::Util's looks_like_number to test whether the input is numeric, and then use int to verify that the number is an integer. You could use a regular expression like /^\d+$/, but there's no guarantee that it works in all circumstances. Using int and looks_like_number guarantees the results.
I assume that a list of integers could be space separated or comma separated or both, thus my split /[\s,]+/.
You said:
The only thing I can think of is getting each integer from the list specifically using STDIN. Is there a better way to do this?
You read in data from a file handle, whether a file or something like STDIN. No way around that. However, you can at least make it a single input rather one at a time which I assume you mean.
By the way, I could have combined my numeric test with:
if( not looks_like_number $integer or $integer != $integer ) {
Since this is an or statement, if this would first check if $input looks numeric, and if it isn't, would warn about the input before checking to see if it's an integer. However, I'm not sure this is actually clearer than making it too separate statements.
#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
use Scalar::Util qw(looks_like_number);
my #integers; # Storage for my integers
#
# Keep looping until you have a valid input
#
INPUT:
for (;;) {
print "List of integers: ";
my $input = <STDIN>;
chomp $input;
#integers = split /[\s,]+/, $input;
#
# Verify inputted "number" is numeric and an integer
#
for my $integer ( #integers ) {
if( not looks_like_number $integer ) {
warn qq(Invalid number entered: "$integer");
next INPUT;
}
if( $integer != int $integer ) {
warn qq(Invalid integer entered: "$integer");
next INPUT;
}
}
#
# Exit if there's at least one integer in #integers
#
last if #integers;
}
say "Integers: " . join ": ", #integers;
This is how I did it:
$input = 0;
while($input != -1)
{
print "add input, finish with -1", "\n";
$input = <STDIN>;
chomp($input);
push(#array, $input);
}
#You also need to remove the last input, -1, with pop:
pop(#array);
print #array;
Console output:
add input, finish with -1
1
add input, finish with -1
2
add input, finish with -1
-1
12
If the user inputs a tab delimited string of numbers directly,
you can use the splice function to separate the strings.
#array = splice(/\t/,$array[0])
Here's one approach, taking a comma-separated list of integers:
my $input = <STDIN>;
chomp($input);
if ($input !~ m/^(\d+(,\d+)*)?$/) { die('invalid input'); }
my #input = split(/,/, $input );
Or you could read one integer per line:
my #input;
while (my $input = <STDIN>) {
chomp($input);
if ($input !~ m/^\d+$/) { die('invalid input'); }
push(#input, $input );
} ## end while
Related
I'm trying to make a program where I need to verify if the user input is the first 2 segments of an IP, I already have the part to verify if the pattern is 000.000 but I'm having problems with verifying if the digits are under 256. Even the when I try to print the #abc array it is blank.
#abc = split(".", $ARGV[0]);
foreach $a (#abc){
if $a != [0 .. 256] {
print "not an ip class"
}
else {
print "it's an ip class"
}
}
Always start your Perl programs with
use strict;
use warnings;
The first argument to split is a regex. You can give it a string, but that will just interpret the contents of the string as a regex at runtime.
. is special in a regex, matching any character. You have to escape it:
my #parts = split /\./, $ARGV[0];
Don't use variables called $a or $b; those are a bit special and used internally by sort.
!= compares two numbers. You can't use it to see if an element is part of a list.
You need to do something like
for my $n (#parts) {
if ($n <= 255) {
print "ok\n";
} else {
print "not ok\n";
}
}
If you have already validated that $n consists of digits only, it cannot be negative.
I want to check that the input from the user is an integer number. I tried the following, but it doesn't work:
try {
print "Enter int";
$num=int(<>);
print "okej";
}
catch (ValueError $e{
print"not int";
}
You really do not want to punish users for leading/trailing spaces (as too many web sites these days seem to be doing), but also avoid leading zeros. Also, make sure the output is flushed before asking for input:
#!/usr/bin/env perl
use strict;
use warnings;
my $input;
until (defined $input) {
local $| = 1;
print 'Enter an integer: ';
($input) = (<STDIN> =~ /\A \s* (-? [1-9] [0-9]* ) \s* \z/x);
}
print "$input\n";
The int function does not check if something is an integer. Instead, it converts its argument to an integer. So, int(1) is 1, int(1.11) is also 1, and int('a') is 0 — with a warning if you enabled warnings.
See also:
"How do I determine whether a scalar is a number/whole/integer/float?" in perlfaq4. You should read the excellent documentation that comes with Perl.
perldoc -v '$|'
Check to see if input has only digits and nothing else...
use warnings;
use strict;
print "Enter integer: ";
my $input = <>;
chomp $input;
print "is int\n" if $input =~ /^[0-9]+$/;
i am new in Perl and i need to do some regexp.
I read, when array is used like integer value, it gives count of elements inside.
So i am doing for example
if (#result = $pattern =~ /(\d)\.(\d)/) {....}
and i was thinking it should return empty array, when pattern matching fails, but it gives me still array with 2 elements, but with uninitialized values.
So how i can put pattern matching inside if condition, is it possible?
EDIT:
foreach (keys #ARGV) {
if (my #result = $ARGV[$_] =~ /^--(?:(help|br)|(?:(input|output|format)=(.+)))$/) {
if (defined $params{$result[0]}) {
print STDERR "Cmd option error\n";
}
$params{$result[0]} = (defined $result[1] ? $result[1] : 1);
}
else {
print STDERR "Cmd option error\n";
exit ERROR_CMD;
}
}
It is regexp pattern for command line options, cmd options are in long format with two hyphens preceding and possible with argument, so
--CMD[=ARG]. I want elegant solution, so this is why i want put it to if condition without some prolog etc.
EDIT2:
oh sry, i was thinking groups in #result array are always counted from 0, but accesible are only groups from branch, where the pattern is success. So if in my code command is "input", it should be in $result[0], but actually it is in $result[1]. I thought if $result[0] is uninitialized, than pattern fails and it goes to the if statement.
Consider the following:
use strict;
use warnings;
my $pattern = 42.42;
my #result = $pattern =~ /(\d)\.(\d)/;
print #result, ' elements';
Output:
24 elements
Context tells Perl how to treat #result. There certainly aren't 24 elements! Perl has printed the array's elements which resulted from your regex's captures. However, if we do the following:
print 0 + #result, ' elements';
we get:
2 elements
In this latter case, Perl interprets a scalar context for #result, so adds the number of elements to 0. This can also be achieved through scalar #results.
Edit to accommodate revised posting: Thus, the conditional in your code:
if(my #result = $ARGV[$_] =~ /^--(?:(help|br)|(?:(input|output|format)=(.+)))$/) { ...
evaluates to true if and only if the match was successful.
#results = $pattern =~ /(\d)\.(\d)/ ? ($1,$2) : ();
Try this:
#result = ();
if ($pattern =~ /(\d)\.(\d)/)
{
push #result, $1;
push #result, $2;
}
=~ is not an equal sign. It's doing a regexp comparison.
So my code above is initializing the array to empty, then assigning values only if the regexp matches.
My script needs to get a series of numbers input by the user and find the average of them. I would like to use the line 'end-of-file' to show that the user is done inputting code. Any help would be appreciated. Below is what I have so far. I think I am really close, but I am missing something.
Code:
#! /usr/bin/perl
use 5.010;
print "Enter the scores and type end-of-file when done";
chomp(#scores = <STDIN>);
foreach (#scores) {
push_average(total(#scores));
}
sub total {
my $sum;
foreach (#_) {
$sum += $_;
}
sum;
}
sub average {
if (#_ == 0) {return}
my $count = #_;
my $sum = total(#_);
$sum/$count;
}
sub push_average {
my $average = average(#_);
my #list;
push #list, $average;
return #list;
}
You are quite close. Adding use strict; use warnings at the top of every Perl script will alert you of errors that might go unnoticed otherwise.
A few hints:
You forgot the sigil of $sum in the last statement of total. Currently, you return a string "sum" (without strict vars), or possibly call a sub called sum.
You don't need the foreach in the main part, rather do
my #averages = push_average(#scores);
The total is already calculated inside push_average
You probably want to print out the resulting average:
my $avg = $averages[0];
say "The average of these numbers is $avg";
The push_average is silly; you return a new array of one element. You could return that one element just as well.
Suggested script:
use strict; use warnings; use 5.010;
use List::Util qw/sum/; # very useful module
# say is like print, but appends a newline. Available with 5.10+
say "Please enter your numbers, finish with Ctrl+D";
my #nums = <STDIN>;
chomp #nums;
# The // is the defined-or operator
# interpolating undef into a string causes a warning.
# Instead, we give an expressive message:
my $avg = average(#nums) // "undefined";
say "The average was $avg";
sub average { #_ ? sum(#_) / #_ : undef } # return undef value if called without args
reads up to the newline. You've got a few choices here. You can ask the user to input the numbers separated by spaces and then split it into your #choices array. Or you can keep asking them to enter a number or just hit enter to finish.
Answer 1)
print "Enter scores separated by a space and press enter when done";
chomp($input = <STDIN>);
#choices = split(' ', $input);
Answer 2)
#chomp = ();
do {
print "Enter a score and then press enter. If done, just press enter.";
chomp($temp = <STDIN>);
if($trim ne '') {
push(#choices, $temp);
}
} until ($temp eq '');
I need to detect if the first character in a file is an equals sign (=) and display the line number. How should I write the if statement?
$i=0;
while (<INPUT>) {
my($line) = $_;
chomp($line);
$findChar = substr $_, 0, 1;
if($findChar == "=")
$output = "$i\n";
print OUTPUT $output;
$i++;
}
Idiomatic perl would use a regular expression (^ meaning beginning of line) plus one of the dreaded builtin variables which happens to mean "line in file":
while (<INPUT>) {
print "$.\n" if /^=/;
}
See also perldoc -v '$.'
Use $findChar eq "=". In Perl:
== and != are numeric comparisons. They will convert both operands to a number.
eq and ne are string comparisons. They will convert both operands to a string.
Yes, this is confusing. Yes, I still write == when I mean eq ALL THE TIME. Yes, it takes me forever to spot my mistake too.
It looks like you are not using strict and warnings. Use them, especially since you do not know Perl, you might also want to add diagnostics to the list of must-use pragmas.
You are keeping track of the input line number in a separate variable $i. Perl has various builtin variables documented in perlvar. Some of these, such as $. are very useful use them.
You are using my($line) = $_; in the body of the while loop. Instead, avoid $_ and assign to $line directly as in while ( my $line = <$input> ).
Note that bareword filehandles such as INPUT are package global. With the exception of the DATA filehandle, you are better off using lexical filehandles to properly limit the scope of your filehandles.
In your posts, include sample data in the __DATA_ section so others can copy, paste and run your code without further work.
With these comments in mind, you can print all lines that do not start with = using:
#!/usr/bin/perl
use strict; use warnings;
while (my $line = <DATA> ) {
my $first_char = substr $line, 0, 1;
if ( $first_char ne '=' ) {
print "$.:$first_char\n";
}
}
__DATA__
=
=
a
=
+
However, I would be inclined to write:
while (my $line = <DATA> ) {
# this will skip blank lines
if ( my ($first_char) = $line =~ /^(.)/ ) {
print "$.:$first_char\n" unless $first_char eq '=';
}
}