In Perl, lets say I have the letter A in variable called $character, and I want it to go up to B, how would I do this? The $character can also be numbers (0-8) and I want the method work on both of them? (Something like binary shift, but not exactly sure if it is something like that). Thanks in advance.
The increment operator may be what you want. However, do make sure that you want the boundary behavior. For instance:
my $character = 'Z';
print ++$character;
Produces:
AA
This is the "with carry" from http://perldoc.perl.org/perlop.html#Auto-increment-and-Auto-decrement.
Simple increment should do what you want:
my $character = "A";
$character++;
from perl-doc:
The auto-increment operator has a little extra builtin magic to it. If
you increment a variable that is numeric, or that has ever been used
in a numeric context, you get a normal increment. If, however, the
variable has been used in only string contexts since it was set, and
has a value that is not the empty string and matches the pattern
/^a-zA-Z*0-9*\z/ , the increment is done as a string, preserving each
character within its range, with carry
Just to add to the other responses:
Note that the magical autoincrement only works if the variable in question has never been used in a numeric context. Thus:
perl -e '$x = "A"; ++$x; print $x' # prints "B"
But:
perl -e '$x = "A"; $x + 0; ++$x; print $x' # prints "1"
To be guaranteed of always getting the magical autoincrement, you should stringify the variable explicitly beforehand:
perl -e '$x = "A"; $x + 0; $x = "$x"; ++$x; print $x' # prints "B"
It may be possible to skip this step if you know the history of the variable you're incrementing and can verify that it has never been used in a numeric context.
Playing with magic can be tricky!
Related
I have the following code snippet in Perl:
my $argsize = #args;
if ($argsize >1){
foreach my $a ($args[1..$argsize-1]) {
$a =~ s/(.*[-+*].*)/\($1\)/; # if there's a math operator, put in parens
}
}
On execution I'm getting "Use of unitialized value $. in range (or flip) , followed by Argument "" isn't numeric in array element at... both pointing to the foreach line.
Can someone help me decipher the error message (and fix the problem(s))? I have an array #args of strings. The code should loop through the second to n't elements (if any exist), and surround individual args with () if they contain a +,-, or *.
I don't think the error stems from the values in args, I think I'm screwing up the range somehow... but I'm failing when args has > 1 element. an example might be:
<"bla bla bla"> <x-1> <foo>
The long and short of it is - your foreach line is broken:
foreach my $a (#args[1..$argsize-1]) {
Works fine. It's because you're using a $ which says 'scalar value' rather than an # which says array (or list).
If you use diagnostics you get;
Use of uninitialized value $. in range (or flip) at
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.
To help you figure out what was undefined, perl will try to tell you
the name of the variable (if any) that was undefined. In some cases
it cannot do this, so it also tells you what operation you used the
undefined value in. Note, however, that perl optimizes your program
and the operation displayed in the warning may not necessarily appear
literally in your program. For example, "that $foo" is usually
optimized into "that " . $foo, and the warning will refer to the
concatenation (.) operator, even though there is no . in
your program.
You can reproduce this error by:
my $x = 1..3;
Which is actually pretty much what you're doing here - you're trying to assign an array value into a scalar.
There's a load more detail in this question:
What is the Perl context with range operator?
But basically: It's treating it as a range operator, as if you were working your way through a file. You would be able to 'act on' particular lines in the file via this operator.
e.g.:
use Data::Dumper;
while (<DATA>) {
my $x = 2 .. 3;
print Dumper $x;
print if $x;
}
__DATA__
line one
another line
third line
fourth line
That range operator is testing line numbers - and because you have no line numbers (because you're not iterating a file) it errors. (But otherwise - it might work, but you'd get some really strange results ;))
But I'd suggest you're doing this quite a convoluted way, and making (potentially?) an error, in that you're starting your array at 1, not zero.
You could instead:
s/(.*[-+*].*)/\($1\)/ for #args;
Which'll have the same result.
(If you need to skip the first argument:
my ( $first_arg, #rest ) = #args;
s/(.*[-+*].*)/\($1\)/ for #rest;
But that error at runtime is the result of some of the data you're feeding in. What you've got here though:
use strict;
use warnings;
my #args = ( '<"bla bla bla">', '<x-1>', '<foo>' );
print "Before #args\n";
s/(.*[-+*].*)/\($1\)/ for #args;
print "After: #args\n";
In Perl, if I have:
no strict;
#ARY = (58, 90);
To operate on an element of the array, say it, the 2nd one, I would write (possibly as part of a larger expression):
$ARY[1] # The most common way found in Perldoc's idioms.
Though, for some reason these also work:
#ARY[1]
#{ARY[1]}
Resulting all in the same object:
print (\$ARY[1]);
print (\#ARY[1]);
print (\#{ARY[1]});
Output:
SCALAR(0x9dbcdc)
SCALAR(0x9dbcdc)
SCALAR(0x9dbcdc)
What is the syntax rules that enable this sort of constructs? How far could one devise reliable program code with each of these constructs, or with a mix of all of them either? How interchangeable are these expressions? (always speaking in a non-strict context).
On a concern of justifying how I come into this question, I agree "use strict" as a better practice, still I'm interested at some knowledge on build-up non-strict expressions.
In an attemp to find myself some help to this uneasiness, I came to:
The notion on "no strict;" of not complaining about undeclared
variables and quirk syntax.
The prefix dereference having higher precedence than subindex [] (perldsc § "Caveat on precedence").
The clarification on when to use # instead of $ (perldata § "Slices").
The lack of "[]" (array subscript / slice) description among the Perl's operators (perlop), which lead me to think it is not an
operator... (yet it has to be something else. But, what?).
For what I learned, none of these hints, put together, make me better understand my issue.
Thanks in advance.
Quotation from perlfaq4:
What is the difference between $array[1] and #array[1]?
The difference is the sigil, that special character in front of the array name. The $ sigil means "exactly one item", while the # sigil means "zero or more items". The $ gets you a single scalar, while the # gets you a list.
Please see: What is the difference between $array[1] and #array[1]?
#ARY[1] is indeed a slice, in fact a slice of only one member. The difference is it creates a list context:
#ar1[0] = qw( a b c ); # List context.
$ar2[0] = qw( a b c ); # Scalar context, the last value is returned.
print "<#ar1> <#ar2>\n";
Output:
<a> <c>
Besides using strict, turn warnings on, too. You'll get the following warning:
Scalar value #ar1[0] better written as $ar1[0]
In perlop, you can read that "Perl's prefix dereferencing operators are typed: $, #, %, and &." The standard syntax is SIGIL { ... }, but in the simple cases, the curly braces can be omitted.
See Can you use string as a HASH ref while "strict refs" in use? for some fun with no strict refs and its emulation under strict.
Extending choroba's answer, to check a particular context, you can use wantarray
sub context { return wantarray ? "LIST" : "SCALAR" }
print $ary1[0] = context(), "\n";
print #ary1[0] = context(), "\n";
Outputs:
SCALAR
LIST
Nothing you did requires no strict; other than to hide your error of doing
#ARY = (58, 90);
when you should have done
my #ARY = (58, 90);
The following returns a single element of the array. Since EXPR is to return a single index, it is evaluated in scalar context.
$array[EXPR]
e.g.
my #array = qw( a b c d );
my $index = 2;
my $ele = $array[$index]; # my $ele = 'c';
The following returns the elements identified by LIST. Since LIST is to return 0 or more elements, it must be evaluated in list context.
#array[LIST]
e.g.
my #array = qw( a b c d );
my #indexes ( 1, 2 );
my #slice = $array[#indexes]; # my #slice = qw( b c );
\( $ARY[$index] ) # Returns a ref to the element returned by $ARY[$index]
\( #ARY[#indexes] ) # Returns refs to each element returned by #ARY[#indexes]
${foo} # Weird way of writing $foo. Useful in literals, e.g. "${foo}bar"
#{foo} # Weird way of writing #foo. Useful in literals, e.g. "#{foo}bar"
${foo}[...] # Weird way of writing $foo[...].
Most people don't even know you can use these outside of string literals.
Following code is showing different output than expected. 'i' should be the ans.
Code:
$var = 'i';
$var++;
print $var;
$var--;
print " * ",$var;
Result:
j ***** -1
Can anyone please explain behavior? I know i am missing a very silly thing.
Thanks
The auto-increment operator ++ is "magical", in that it can also increment non-numerical strings. So i becomes j. The auto-decrement operator -- does not have this "magic" feature. Therefore the string j is converted to a number, which will be 0, then decremented to -1.
This is documented in perldoc perlop:
The auto-increment operator has a little extra builtin magic to it. If
you increment a variable that is numeric, or that has ever been used
in a numeric context, you get a normal increment. If, however, the
variable has been used in only string contexts since it was set, and
has a value that is not the empty string and matches the pattern
/^[a-zA-Z][0-9]\z/ , the increment is done as a string, preserving
each character within its range, with carry:
print ++($foo = "99"); # prints "100"
print ++($foo = "a0"); # prints "a1"
print ++($foo = "Az"); # prints "Ba"
print ++($foo = "zz"); # prints "aaa"
undef is always treated as numeric, and in particular is changed to 0
before incrementing (so that a post-increment of an undef value will
return 0 rather than undef).
The auto-decrement operator is not magical.
There is no type char in perl. 'i' is the same string as "i". The question is why ++ does increase the value of the char. This question has been discussed here: Increment (++) and decrement (--) strings in Perl
I know a little bit perl, but not enough deeply to understand the next.
Reading perldelta 5.18 i found the next piece of code what is already disabled in 5.18. Not counting this, still want understand how it's works.
Here is the code and in the comments are what i understand
%_=(_,"Just another "); #initialize the %_ hash with key=>value _ => 'Just another'
$_="Perl hacker,\n"; #assign to the $_ variable with "Perl..."
s//_}->{_/e; # darkness. the /e - evauates the expression, but...
print
it prints:
Just another Perl hacker,
I tried, the perl -MO=Deparse and get the next
(%_) = ('_', 'Just another '); #initializing the %_ hash
$_ = "Perl hacker,\n"; # as above
s//%{'_';}/e; # substitute to the beginning of the $_ - WHAT?
print $_; # print the result
japh syntax OK
What is strange (at least for me) - running the "deparsed" code doesn't gives the original result and prints:
1/8Perl hacker,
I would be very happy:
if someone can explain the code, especially if someone could write an helper code, (with additional steps) what helps me understand how it is works - what happens.
explain, why the deparsed code not prints the original result.
What means the %{'_';} in the deparsed code?
The code actually executed by the substitution operator is probably actually something like
my $code = "do { $repl_expr }";
So when the replacement expression is _}->{_, the following is executed:
do { _}->{_ }
_ simply returns the string _ (since strict is off), so that's the same as
do { "_" }->{_}
which is the same as
"_"->{_}
What you have there is a hash element dereference, where the reference is a symbolic reference (i.e. a string rather than an actual reference). Normally forbidden by strict, here's an example of a symbolic reference at work:
%h1 = ( id => 123 );
%h2 = ( id => 456 );
print "h$_"->{id}, "\n"
for 1..2;
So that means
"_"->{_} # Run-time symbol lookup
is the same as
$_{_} # Compile-time symbol lookup
A similar trick is often used in one-liners.
perl -nle'$c += $_; END { print $c }'
can be shortened to
perl -nle'$c += $_; }{ print $c'
Because the code actually executed when -n is used is obtained from something equivalent to
my $code = "LINE: while (<>) { $program }";
%{'_';}
is a very weird way to write
%{'_'}
which is a hash dereference. Again, the reference here is a symbolic reference. It's equivalent to
%_
In scalar context, hash current returns a value that reports some information about that hash's internals (or a false value if empty). There's been a suggestion to change it to return the number of keys instead.
I know that there is a library that do that
use Scalar::Util qw(looks_like_number);
yet I want to do it using perl regular expression. And I want it to work for double numbers not for only integers.
so I want something better than this
$var =~ /^[+-]?\d+$/
thanks.
Constructing a single regular expression to validate a number is really difficult. There simply are too many criteria to consider. Perlfaq4 contains a section "How do I determine whether a scalar is a number/whole/integer/float?
The code from that documentation shows the following tests:
if (/\D/) {print "has nondigits\n" }
if (/^\d+$/) {print "is a whole number\n" }
if (/^-?\d+$/) {print "is an integer\n" }
if (/^[+-]?\d+$/) {print "is a +/- integer\n" }
if (/^-?\d+\.?\d*$/) {print "is a real number\n" }
if (/^-?(?:\d+(?:\.\d*)?|\.\d+)$/) {print "is a decimal number\n"}
if (/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) {
print "is a C float\n"
}
The first test disqualifies an unsigned integer.
The second test qualifies a whole number.
The third test qualifies an integer.
The fourth test qualifies a positive/negatively signed integer.
The fifth test qualifies a real number.
The sixth test qualifies a decimal number.
The seventh test qualifies a number in c-style scientific notation.
So if you were using those tests (excluding the first one) you would have to verify that one or more of the tests passes. Then you've got a number.
Another method, since you don't want to use the module Scalar::Util, you can learn from the code IN Scalar::Util. The looks_like_number() function is set up like this:
sub looks_like_number {
local $_ = shift;
# checks from perlfaq4
return $] < 5.009002 unless defined;
return 1 if (/^[+-]?\d+$/); # is a +/- integer
return 1 if (/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/); # a C float
return 1 if ($] >= 5.008 and /^(Inf(inity)?|NaN)$/i)
or ($] >= 5.006001 and /^Inf$/i);
0;
}
You should be able to use the portions of that function that are applicable to your situation.
I would like to point out, however, that Scalar::Util is a core Perl module; it ships with Perl, just like strict does. The best practice of all is probably to just use it.
You should use Regexp::Common, most patterns are more complicated than you realize.
use Regexp::Common;
my $real = 3.14159;
print "Real" if $real =~ /$RE{num}{real}/;
However, the pattern is not anchored by default, so a stricter version is:
my $real_pat = $RE{num}{real};
my $real = 3.14159;
print "Real" if $real =~ /^$real_pat$/;
Well first you should make sure that the number does not contain any commas so you do this:
$var =~ s/,//g; # remove all the commas
Then create another variable to do the rest of the compare.
$var2=$var;
Then remove the . from the new variable yet only once occurrence.
$var2 =~ s/.//; # replace . with nothing to compare yet only once.
now var2 should look like an integer with no "."
so do this:
if($var2 !~ /^[+-]?\d+$/){
print "not valid";
}else{
#use var1
}
you can fix this code and write it as a function if you need to use it more than once.
Cheers!