Perl if Statement only specific length of numbers - perl

is it possible to have an if-statement where I look if my $expression has less than 12 integers and only integers. Like
if($expression> less than 12numbers and only integers).

You can match it using regex. Below is the code snippet.
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(say);
my $exp = "1234567898711";
if ($exp =~ /^\d{12}$/) {
say "Matched expression: $exp";
} else {
say "Not matched";
}
EDIT:
If you want to look for 12 digits or less than that use below expression:
\d{1,12}
Note: This expression is only when you have straight digits. If its a alphanumeric, then it needed to be changed accordingly.

Related

Chopping the last sequence of a pattern

I have this series of values
rd_8KB_rms
rd_8KB_rms_qd1
rd_8KB_wh
rd_8KB_wh_q1
rd_8KB_wms
rd_8KB_wms_qd1
rd_256K_rms
rd_256K_rms_1
and where there are 3 underscores I would like to chop the last underscore and the characters that trail it ( which are variable in number). I think I have tried variations of substr, split, regex but can't find anything that works
You can use transliteration tr/_// to count the number of underscores and substitution s/_[^_]*$// to remove the part from the last underscore to the end.
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
while (<DATA>) {
chomp;
s/_[^_]*$// if tr/_// == 3;
say;
}
__DATA__
rd_8KB_rms
rd_8KB_rms_qd1
rd_8KB_wh
rd_8KB_wh_q1
rd_8KB_wms
rd_8KB_wms_qd1
rd_256K_rms
rd_256K_rms_1
If there can be even more underscores, use a variant like
s/_[^_]*$// until tr/_// <= 3;

truncate string in perl into substring with trailing elipses

I'm trying to truncate a string in a select input option using perl if it is longer than a set value, though i can't get it to work correctly.
my $value = defined $option->{value} ? $option->{value} : '';
my $maxValueLength = 50;
if ($value.length > $maxValueLength) {
$value = substr $value, 0, $maxValueLength + '...';
}
Another option is regex
$string =~ s/.{$maxLength}\K.*/.../;
It matches any character (.) given number of times ({N}, here $maxLength), what is the first $maxLength characters in $string; then \K makes it "forget" all previous matches so those won't get replaced later. The rest of the string that is matched is then replaced by ...
See Lookaround assertions in perlre for \K.
This does start the regex engine for a simple task but it doesn't need any conditionals -- if the string is shorter than the maximum length the regex won't match and nothing happens.
Your code has several syntax errors. Turn on use strict and use warnings if you don't have it, and then read the error messages it tells you about. This is a bit tricky because of Perl's very complex syntax (see also Damian Conway's keynote from the 2020 Perl and Raku Conference), but it boils down to these:
Use of uninitialized value in concatenation (.) or string at line 7
Argument "..." isn't numeric in addition (+) at line 8
I've used the following adaption of your code to produce these
use strict;
use warnings;
my $value = '1234567890' x 10;
my $maxValueLength = 50;
if ( $value.length > $maxValueLength ) {
$value = substr $value, 0, $maxValueLength + '...';
}
print $value;
Now let's see what they mean.
The . operator in Perl is a concatenation. You cannot use it to call methods, and length is not a method on a string. Perl thinks you are using the built-in length (a function, not a method) without an argument, which makes it default to $_. Most built-ins do this, to make one-liners shorter. But $_ is not defined. Now the . tries to concatenate the length of undef to $value. And using undef in a string operation leads to this warning.
The correct way of doing this is length $value (or with parentheses if you prefer them, length($value)).
The + operator is not concatenation (we just learned that the . is). It's a numerical addition. Perl is pretty good at converting between strings and numbers as there aren't really any types, so saying 1 + "5" would give you 6 without problems, but it cannot do that for a couple of dots in a string. Hence it complains about a non-number value in an addition.
You want the substring with a given length, and then you want to attach the three dots. Because of associativity (or stickyness) of operators you will need to use parentheses () for your substr call.
$value = substr($value, 0, $maxValueLength) . '...';
To find a length of the string use length(STRING)
Here is the code snippet how you can modify the script.
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(say);
my $string = "abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz";
say "length of original string is:".length($string);
my $value = defined $string ? $string : '';
my $maxValueLength = 50;
if (length($value) > $maxValueLength) {
$value = substr $value, 0, $maxValueLength;
say "value:$value";
say "value's length:".length($value);
}
Output:
length of original string is:80
value:abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvw
value's length:50

Arithmetic with strings that contain numbers

What is the Perlish way to deal with arithmetic with strings that contain numbers?
Example: Say I'm dealing with font sizes that are represented with a string like -> "120px". I know the values of font sizes will always be formatted with number characters followed by non-number characters and I know that Perl will truncate any trailing characters of a string in arithmetic so could I do something like the following(with appropriate comments)?
#! /usr/bin/env perl
use warnings;
use strict;
use utf8;
use constant FONT_UNIT => 4;
my $font_size = "120px";
STDOUT->print("${font_size}\n");
$font_size = do {no warnings; $font_size + FONT_UNIT}."px";
STDOUT->print("${font_size}\n");
exit (0);
I ask because this feature of the language really works here.
Yes, your approach seems ok. You can also use substitution with evaluation:
$font_size =~ s/([0-9]+)/$1 + FONT_UNIT/e;
Or, if you need clarity, just extract the number, change it, and glue the parts back:
my ($size, $unit) = $font_size =~ /([0-9]+)(.*)/;
$size += FONT_UNIT;
STDOUT->say("$size$unit");
The only two suggestions I'd make would be to be more precise about which warnings you're turning off and to use a slightly larger naked code block to make it more readable.
#! /usr/bin/env perl
use warnings;
use strict;
use utf8;
use constant FONT_UNIT => 4;
my $font_size = "120px";
STDOUT->print("${font_size}\n");
{
no warnings 'numeric';
$font_size = $font_size + FONT_UNIT . "px";
}
STDOUT->print("${font_size}\n");
exit (0);
What is the Perlish way to deal with arithmetic with strings that contain numbers?
Leading and trailing whitespace is ignored (without generating a warning).
inf, infinity, nan, case insensitive, after stripping whitespace, and with optional leading + or -, are treated as those special numbers (without generating a warning).
0 but true (no extra whitespace allowed) is treated as the number 0 (without generating a warning).
Any leading thing that looks like an integer or decimal number with an optional following e or E and optionally signed exponent is treated as that number (to the extent it can be represented in a numeric type). If any non-whitespace characters remain afterwards, an "isn't numeric" warning is generated.

Why does "bob" == "godzilla" in Perl?

In Perl class today, a student turned in an assignment which vexes me. We are studying ARGV, but the result was not what I expected. His program (meme.pl) was:
#!/usr/bin/perl
$A = $ARGV[0];
chomp($A);
if ($A == "godzilla"){
print "$A\n";
}
else {
print "We need a monster's name\n";
}
If I type:
% ./meme.pl bob
the result is
% bob
So the variable assignment works, and but the condition ($A == "godzilla") is true no matter what is typed on the command line. I expected that since $ARGV[0] is "bob" and $A=$ARGV[0], then it should not true that $A="godzilla."
What am I missing? I have combed through this code for hours, and I know I am just overlooking some small thing.
Use eq, not ==, to test string equality:
if ($A eq "godzilla"){
More information is available at perldoc perlop.
Note: Adding use strict; and use warnings; to the top of your script would have led you in the right direction.
use strict; and use warnings; should be on...instant F in my book.
But no...evaluations of strings using "==" evaluate all strings - except those that start with a number like '123bob' (see comment below) - as numerical 0. That is why it is evaluating to true - it's "turning into" the statement 0 == 0. use warnings; would have told you something was up.
As many have said - use eq for strings.
More evidence and options can be found here: (http://perlmeme.org/howtos/syntax/comparing_values.html)
The pertinent excerpt (example program):
#!/usr/bin/perl
use strict;
use warnings;
my $string1 = 'three';
my $string2 = 'five';
if ($string1 == $string2) {
print "Equal\n";
} else {
print "Not equal\n";
}
From the above example, you would get warning messages and both strings would evaluate to zero:
Argument "five" isn't numeric in numeric eq (==) at ./test.pl line 8.
Argument "three" isn't numeric in numeric eq (==) at ./test.pl line 8.
Equal
You aren't getting those warnings...just the "Equal", thanks to the absence of use warnings; at the top of your - errr...your student's...cough... - code. ;)
When you are comparing strings, you must use "eq" instead of "==". So replace
($A == "godzilla")
by
($A eq "godzilla")
What the others said is correct about using eq to compare strings. However, the test passes, because when compared numerically with == the string 'bob' and the string 'godzilla' both evaluate to 0, so the test passes and you get bob.

Is 999...9 a real number in Perl?

sub is_integer {
defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
}
sub is_float {
defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/;
}
For the code mentioned above, if we give input as 999999999999999999999999999999999999999999, it is giving output as not real number.
Why it is behaving like that?
I forgot to mention one more thing:
If I am using this code for $x as the above value:
if($x > 0 || $x <= 0 ) {
print "Real";
}
Output is real.
How is this possible?
$ perl -e 'print 999999999999999999999999999999999999999999'
1e+42
i.e. Perl uses scientific representation for this number and that is why your regexp doesn't match.
Use the looks_like_number function from Scalar::Util (which is a core module).
use Scalar::Util qw( looks_like_number );
say "Number" if looks_like_number 999999999999999999999999999999999999999999;
# above prints "Number"
Just to add one more thing. As others have explained, the number you are working with is out of range for a Perl integer (unless you are on a 140 bit machine). Therefore, the variable will be stored as a floating point number. Regular expressions operate on strings. Therefore, the number is converted to its string representation before the regular expression operates on it.
Others have explained what is going on: out of the box, Perl can't handle numbers that large without using scientific notation.
If you need to work with large numbers, take a look at bignum or its components, such as Math::BigInt. For example:
use strict;
use warnings;
use Math::BigInt;
my $big_str = '900000000000000000000000000000000000000';
my $big_num = Math::BigInt->new($big_str);
$big_num ++;
print "Is integer: $big_num\n" if is_integer($big_num);
sub is_integer {
defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
}
Also, you may want to take a look at bignum in the Perl documentation.