I have a validation check when I pass the command line parameters to the perl program.I pass two years first passed argument should be lesser than the second passed argument and both the arguments should be only digits and also they should be exactly 4.
#Sunny>perl check.pl 2007 2008 This is good
#Sunny>perl check.pl 2008 2007 This is bad
#Sunny>perl check.pl 200 2007 This is bad
I have written code for this but not able to figure it out why its not working.
#!usr/bin/perl
#check.pl
if ($#ARGV < 0) { }
else
{
$fiscyear1 = $ARGV[0];
$fiscyear2 = $ARGV[1];
}
if (($fiscyear1 !~ m/\d{4}/) and ($fiscyear2 !~ m/\d{4}/) and ($fiscyear1 < $fiscyear2))
{ print "Bad parameters\n"; }
else
{ print "good parameters\n"; }
This sounds like a bad case of overthinking things...
What you want is to verify that the arguments are two years, in the form YYYY, and that the second year comes after the first.
Well, 9999 would pass any digit check, but it is hardly a valid year. Same with 0101, or 3021, etc.
What you want is to set a given range, and make sure the arguments are numeric.
use strict;
use warnings;
my $yr1 = shift;
my $yr2 = shift || usage();
usage() unless $yr1 =~ /^\d+$/;
usage() unless $yr2 =~ /^\d+$/;
my $min_year = 1900;
my $max_year = 2200;
if ( ($yr1 < $min_year) or ($yr1 > $max_year) ) {
die "Invalid year: $yr1";
}
if ( ($yr2 < $min_year) or ($yr2 > $max_year) ) {
die "Invalid year: $yr2";
}
if ( $yr1 >= $yr2 ) {
die "Invalid sequence: $yr2 is not greater than $yr1";
}
sub usage {
die "Usage script.pl <year1> <year2>";
}
What about this:
if (($fiscyear1 !~ m/^\d{4}$/) or ($fiscyear2 !~ m/^\d{4}$/) or ($fiscyear1 > $fiscyear2))
{ print "Bad parameters\n"; }
I changed the ands in ors and also the final < into > (since you want the first argument is less than the second)
EDIT:
It seems that it works in my case:
I also very strongly accept the advice of using ^$, and have modified my answer accordingly.
You are missing start and end of string ^ and $ in regexps (without them it can match 5 or more symbols):
use strict; use warnings;
my ($fiscyear1, $fiscyear2) = #ARGV;
if ($fiscyear1 =~ m{^\d{4}$} && $fiscyear2 =~ m{^\d{4}$} && $fiscyear1 < $fiscyear2) {
print "good parameters\n";
} else {
print "Bad parameters\n";
}
Update
You can also use unless here like:
unless ($fiscyear1 =~ m{^\d{4}$} && $fiscyear2 =~ m{^\d{4}$} && $fiscyear1 < $fiscyear2) {
print "Bad parameters\n";
exit(1); ## tells the caller side that there is an error
}
print "good parameters\n";
Related
The below code is giving an error when I use if-else block for the comparison of $valid. When if-else condition is not used the error is not there. The error is " Use of uninitialized value $value in regexp compilation".How to solve this?
...
if($valid eq 1){
print "Enter value\n" ;
my $value = <STDIN>;
}else{
print " valid is not 1 \n";
}
if($line =~ /$string.*$value/){ --> error
//code
}
Perl program needs (pragma: A pragma is a module which influences some aspect of the compile time or run time behaviour of Perl, such as strict or warnings). Unless until we see the full code.
Please understand the declaration of the variables inside the block and outside of the block.
Coming to your code:
if($valid eq 1)
{
print "Enter value\n" ;
my $value = <STDIN>;
#This the "$value" prints what you have get from the MS-Dos Prompt from the user.
#$value ends here since the $value has been declared this block
}
$value needs to declare outside the if-else block you won't get the error message.
my $value = "";
if($valid eq 1)
{
print "Enter value\n" ;
$value = <STDIN>;
chomp($value); #Additionally, you should chomp (remove the entermark at end of the value $value;
}
Thanks.
I took some liberty to alter your code to make it work
[enter dog or cat at the prompt for a test]
use strict;
use warnings;
my $valid = '1';
my $value;
my $line = 'Some lazy dog is taking a sun bath';
my $string = 'lazy';
if($valid eq '1'){
print "Enter value: " ;
$value = <STDIN>;
chomp $value;
}else{
print " valid is not 1 \n";
}
if( $line =~ /$string.*$value/ ){
print 'Horay!!! I found the string - ';
print "$line\n";
} else {
print "Sorry, no line found\n";
}
Your error is hidden in scope declaration of $value -- it is only valid for if internal block of code - I have moved it outside of if ... else ... block.
NOTE: perhaps you intended to write
my $valid = 1;
....
if( $valid ) {
....
} else {
....
}
although the following code is valid but in this particular case is excessive (if $valid is not zero it considered true)
if( $valid == 1 ) {
....
} else {
....
}
Comparison operators for numbers and strings
Just like the title laboriously explains, I'm looking for a way to pass matches from individual elements in an existing array into uninitialized variables stored in an existing array, i.e. consider the following:
my $data1;
my $data2;
my $data3;
my #data_pod(
$data1,
$data2,
$data3
);
my #array ( "a1", "b1", "c1" );
foreach (#array)
{
#GET RID OF THE 1'S BY A PATTERN MATCH
#STORE THE RESULT IN APPROPRIATE ELEMENT OF date_pod
}
The end result should make this
foreach (#data_pod)
{
print "$_\r\n";
}
produce this
a
b
c
Just assume that the match only matches singleton lowercase alphabetic characters. Of course, this is a metaphor to get at what I'm really after. I'm thinking along the lines of something akin to the following:
foreach my $cat (#quarters)
{
push #slim_quarters, $cat =~ /[A-Z][a-z]*, [A-Z][a-z]* \d*/g;
}
n.b. - I'm new to Perl. I'm a baby.
use Date::Calc qw( Today Date_to_Days Now );
# MIGHT BE ABLE TO USE THIS / MODIFY
# Lower Limit
my $year1 =;
my $month1 = 7;
my $day1 = $slim_quarters[0];
my $hour1 = 00;
my $min1 = 00;
my $minlower = ($hour1 * 60) + $min1;
# Upper Limit
my $year2 = 2001;
my $month2 = 7;
my $day2 = 6;
my $hour2 = 20;
my $min2 = 59;
my $minupper = ($hour2 * 60) + $min2;
# Current System Time
my $now = localtime();
print $now, "\n";
# Get current time from module
($year, $month, $day) = Today();
($hour, $min,) = Now();
my $minnow = ($hour * 60) + $min;
print "It is now $hour:$min or $minnow minutes since midnight\n";
$lower = Date_to_Days($year1, $month1, $day1);
$upper = Date_to_Days($year2, $month2, $day2);
$date = Date_to_Days($year, $month, $day);
print "$lower=lower\t$upper=upper\t$date=date\n";
if (($date >= $lower) && ($date <= $upper)) {
if (($date != $lower) && ($date != $upper)) {
print "Not on a start and stop day\n";
}
elsif (($date == $lower) && ($date == $upper)) {
print "same start and stop date\n";
if (($minnow >= $minlower) && ($minnow < $minupper)) {
print "match on dates and mins within range\n";
}
else {
print "BUT not within minute range\n";
exit();
}
}
elsif (($date == $lower) && ($minnow < $minlower)) {
print "before start time\n";
exit();
}
elsif (($date == $upper) && ($minnow > $minupper)) {
print "after end time\n";
exit();
}
print "GOOD\n";
}
else {
print "out of range\n";
}
This is a classic XY problem. I'll attempt to answer the question you should have asked instead of the question you actually asked.
Based on your comments, the crux of your problem seems to be parsing and comparing dates. Time::Piece, a core module since Perl 5.10, can handle both of these tasks:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $format = '%A, %B %d';
# Parse
my $t1 = Time::Piece->strptime('Monday, June 13', $format);
my $t2 = Time::Piece->strptime('Friday, June 17', $format);
# Compare
say 't1 > t2' if $t1 > $t2;
say 't2 > t1' if $t2 > $t1;
# Print
say $_->strftime('%B %d') for $t1, $t2;
Output:
t2 > t1
June 13
June 17
Well I think you may have started with the wrong design, but this will work for you. If you tell us more about the steps you took to conclude that this is what you want then I am sure we can help.
use strict;
use warnings;
use feature 'say';
my #data_pod = \my ($data1, $data2, $data3);
my #array = qw( a1 b1 c1 );
for my $i (0 .. $#array) {
${ $data_pod[$i] } = $array[$i] =~ s/1//r;
}
say for $data1, $data2, $data3;
output
a
b
c
I was trying to make a program to match the string which must contains number of 0-9 using regex.
This was correct but it somehow seems long. Do anyone has alternatives for this code?
if($str = (preg_match('/[1]/', $str) && preg_match('/[2]/', $str)
&& preg_match('/[3]/', $str) && preg_match('/[4]/', $str)
&& preg_match('/[5]/', $str) && preg_match('/[6]/', $str)
&& preg_match('/[7]/', $str) && preg_match('/[8]/', $str)
&& preg_match('/[9]/', $str) && preg_match('/[0]/', $str))) {
//do something
}
Simply use a character range: [0-9].
if (preg_match('/[0-9]/', $str)) {
echo 'It does.';
} else {
echo 'It doesn\'t.';
}
If you were ever in a situation where you wouldn't want "6" you could even change it to [012345789] if you really want to.
As Floris mentions, your code is pretty confusing - if you want all the characters to be displayed individually at least once, you can simply use strpos with a loop:
<?php
$match = true;
for ($i = 0; $i < 9; $i++) {
if (strpos($string, (string)$i) === false) {
$match = false;
break; //No need to continue the loop - we already got our answer
}
}
if ($match) {
echo 'Yes!';
} else {
echo 'No!';
}
?>
Alternatively, I apparently already gave you a function to do this?
Looks like you have all the conditions ANDed together. In that following lookahead based regex should work for you:
preg_match('/(?=[^0]*0)(?=[^1]*1)(?=[^2]*2)(?=[^3]*3)(?=[^4]*4)(?=[^5]*5)(?=[^6]*6)(?=[^7]*7)(?=[^8]*8)(?=[^9]*9)./', $str)
If you want to make sure that your string contains all the digits 0-9, you should probably strip anything that is not a digit, then take unique characters only, and make sure the string length is 10. This is more compact than your expression but not necessarily faster. The php function count_chars does much of this work (using mode = 3):
$str = "12345abcde789d9999969";
preg_match_all('/\d+/', $str, $matches);
$distinct = strlen(count_chars(join($matches[0]),3));
if($distinct==10)
{
echo "all ten digits are present<br>";
}
else
{
echo "not all digits are present<br>";
}
echo "there are " . $distinct . " distinct digits<br>";
Output of the above:
not all digits are present
there are 9 distinct digits
I have a string in a variable $vreponse and the string is
int.force_snmp_version T_SIZE 3
All I want to do is verify if there is number 3 in the string. If the verification is success print a message or else print fail message
I have tried something like this
my $vresponse = $ua->get("https://$user:$pass\#$ern_ip/get_param?p=init.force_snmp_version");
if ($vresponse->decoded_content =~ /\b3$/)
{
print "SUCESS\n";
}
else
{ print "not\n"; }
This is not working, do I need to change $vresponse->decoded_content ?
Maybe just
if ( $vresponse =~ /3/ ) { ... }
which just checks that there is a 3 character somewhere in the string.
Or, more precisely
if ( $vresponse =~ /\b3$/ ) { ... }
which check that the last character is 3 and it is alone, i.e. not the end of, say, 23.
my $vresponse = 'int.force_snmp_version T_SIZE 3';
my $char = '3';
my $result = index($vresponse , $char);
if ($result >=0)
{
#display found
}
else
{
#display not found
}
How can I find the number of times a word is in a block of text in Perl?
For example my text file is this:
#! /usr/bin/perl -w
# The 'terrible' program - a poorly formatted 'oddeven'.
use constant HOWMANY => 4; $count = 0;
while ( $count < HOWMANY ) {
$count++;
if ( $count == 1 ) {
print "odd\n";
} elsif ( $count == 2 ) {
print "even\n";
} elsif ( $count == 3 ) {
print "odd\n";
} else { # at this point $count is four.
print "even\n";
}
}
I want to find the number of "count" word for that text file. File is named terrible.pl
Idealy it should use regex and with minimum number of line of code.
EDIT: This is what I have tried:
use IO::File;
my $fh = IO::File->new('terrible.pl', 'r') or die "$!\n";
my %words;
while (<$fh>) {
for my $word ($text =~ /count/g) {
print "x";
$words{$word}++;
}
}
print $words{$word};
Here's a complete solution. If this is homework, you learn more by explaining this to your teacher than by rolling your own:
perl -0777ne "print+(##=/count/g)+0" terrible.pl
If you are trying to count how many times appears the word "count", this will work:
my $count=0;
open(INPUT,"<terrible.pl");
while (<INPUT>) {
$count++ while ($_ =~ /count/g);
}
close(INPUT);
print "$count times\n";
I'm not actually sure what your example code is but you're almost there:
perl -e '$text = "lol wut foo wut bar wut"; $count = 0; $count++ while $text =~ /wut/g; print "$count\n";'
You can use the /g modifier to continue searching the string for matches. In the example above, it will return all instances of the word 'wut' in the $text var.
You can probably use something like so:
my $fh = IO::File->new('test.txt', 'r') or die "$!\n";
my %words;
while (<$fh>) {
for my $word (split / /) {
$words{$word}++;
}
}
That will give you an accurate count of every "word" (defined as a group of characters separated by a space), and store it in a hash which is keyed by the word with a value of the number of the word which was seen.
perdoc perlrequick has an answer. The term you want in that document is "scalar context".
Given that this appears to be a homework question, I'll point you at the documentation instead.
So, what are you trying to do? You want the number of times something appears in a block of text. You can use the Perl grep function. That will go through a block of text without needing to loop.
If you want an odd/even return value, you can use the modulo arithmetic function. You can do something like this:
if ($number % 2) {
print "$number is odd\n"; #Returns a "1" or true
}
else {
print "$number is even\n"; #Returns a "0" or false
}