- - not working properly on char in perl - perl

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

Related

Perl go up a character?

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!

Warnings on equality operators

Has something changed in Perl or has it always been this way, that examples like the second ($number eq 'a') don't throw a warning?
#!/usr/bin/env perl
use warnings;
use 5.12.0;
my $string = 'l';
if ($string == 0) {};
my $number = 1;
if ($number eq 'a') {};
# Argument "l" isn't numeric in numeric eq (==) at ./perl.pl line 6.
Perl will be try to convert a scalar to the type required by the context where it is used.
There is a valid conversion from any scalar type to a string, so this is always done silently.
Conversion to a number is also done silently if the string passes a looks_like_number test (accessible through Scalar::Util). Otherwise a warning is raised and a 'best guess' approximation is done anyway.
my $string = '9';
if ( $string == 9 ) { print "YES" };
Converts the string silently to integer 9, the test succeeds and YES is printed.
my $string = '9,8';
if ( $string == 9 ) { print "YES" };
Raises the warning Argument "9,8" isn't numeric in numeric eq (==), converts the string to integer 9, the test succeeds and YES is printed.
To my knowledge it has always been this way, at least since v5.0.
It has been that way.
In the first if, l is considered to be in numeric context. However, l cannot be converted to a number. Therefore, a warning is emitted.
In the second if, the number 1 is considered to be in string context. Therefore the number 1 is converted to the string '1' before comparison and hence no warnings are emitted.
Did you use a lowercase "L" on purpose? It's often hard to tell the difference between a lowercase "L" and one. You would have answered your own question if you had used a one instead.
>perl -wE"say '1' == 0;"
>perl -wE"say 1 eq 'a';"
>
As you can see,
If one needs a number, Perl will convert a string to a number without warning.
If one needs a string, Perl will convert a number to a string without warning.
Very consistent.
You get a warning when you try to convert a lowercase L to a number, but how is that surprising?

Why does print ($a = a..c) produce: 1E0

print (a..c) # this prints: abc
print ($a = "abc") # this prints: abc
print ($a = a..c); # this prints: 1E0
I would have thought it would print: abc
use strict;
print ($a = "a".."c"); # this prints 1E0
Why? Is it just my computer?
edit: I've got a partial answer (the range operator .. returns a boolean value in scalar context - thanks) but what I don't understand is:
why does: print ($a = "a"..."c") produce 1 instead of 0
why does: print ($a = "a".."c") produce 1E0 instead of 1 or 0
There are a number of subtle things going on here. The first is that .. is really two completely different operators depending on the context in which it's called. In list context it creates a list of values (incrementing by one) between the given starting and ending points.
#numbers = 1 .. 3; # 1, 2, 3
#letters = 'a' .. 'c'; # a, b, c (Yes, Perl can increment strings)
Because print interprets its arguments in list context
print 'a' .. 'c'; # <-- this
print 'a', 'b', 'c'; # <-- is equivalent to this
In scalar context, .. is flip-flop operator. From Range Operators in perlop:
It is false as long as its left operand is false. Once the left
operand is true, the range operator stays true until the right operand
is true, AFTER which the range operator becomes false again.
Assignment to a scalar value as in $a = ... creates scalar context. That means that the .. in print ($a = 'a' .. 'c') is an instance of the flip-flop operator, not the list creation operator.
The flip-flop operator is designed to be used when filtering lines in a file. e.g.
while (<$fh>) {
print if /first/ .. /last/;
}
would print all of the lines in a file starting with the one that contained first and ending with the one that contained last.
The flip-flop operator has some additional magic designed to make it easy to filter based on the line number.
while (<$fh>) {
print if 10 .. 20;
}
will print lines 10 through 20 of a file. It does this by employing special case behavior:
If either operand of scalar .. is a constant expression, that
operand is considered true if it is equal (==) to the current input
line number (the $. variable).
The strings a and c are both constant expressions so they trigger this special case. They aren't numbers, but they're used as numbers (== is a numeric comparison). Perl will convert scalar values between strings and numbers as needed. In this case, both values nummify to 0. Therefore
print ($a = 'a' .. 'c'); # <-- this
print ($a = 0 .. 0); # <-- is effectively this
print ($a = ($. == 0) .. ($. == 0)); # <-- which is really this
We're getting close to the bottom of the mystery. On to the next bit. More from perlop:
The value returned is either the empty string for false, or a sequence
number (beginning with 1) for true. The sequence number is reset for
each range encountered. The final sequence number in a range has the
string "E0" appended to it
If you haven't read any lines from a file yet, $. will be undef which is 0 in a numerical context. 0 == 0 is true, so the .. returns a true value. It's the first true value, so it's 1. Because both the left-hand and right-hand sides are true the first true value is also the last true value and the E0 "this is the last value" suffix is appended to the return value. That is why print ($a = 'a' .. 'c') prints 1E0. If you were to set $. to a non-zero value the .. would be false and return the empty string.
print ($a = 'a' .. 'c'); # prints "1E0"
$. = 1;
print ($a = 'a' .. 'c'); # prints nothing
The very final piece of the puzzle (and I might be going too far now) is that the assignment operator returns a value. In this case that's the value assigned to $a1 -- 1E0. This value is what is ultimately spit out by the print.
1: Technically, the assignment produces a lvalue for the item assigned to. i.e. it returns an lvalue for the variable $a which then evaluates to 1E0.
It's a matter of list context vs. scalar context, as explained in perldoc perlop:
In scalar context, ".." returns a boolean value. The operator is
bistable, like a flip-flop, and emulates the line-range (comma)
operator of sed, awk, and various editors. Each ".." operator
maintains its own boolean state, even across calls to a subroutine
that contains it. It is false as long as its left operand is false.
Once the left operand is true, the range operator stays true until the
right operand is true, AFTER which the range operator becomes false
again. It doesn't become false till the next time the range operator
is evaluated. It can test the right operand and become false on the
same evaluation it became true (as in awk), but it still returns true
once. If you don't want it to test the right operand until the next
evaluation, as in sed, just use three dots ("...") instead of two. In
all other regards, "..." behaves just like ".." does.
[snip]
The final sequence number in a range has the string "E0" appended to
it, which doesn't affect its numeric value, but gives you something to
search for if you want to exclude the endpoint.
EDIT in response to DanD man's comment:
I find it a bit hard to digest too; frankly, I rarely use the .. operator, and even more rarely in scalar context. But for example, the expression 5..10 in an input loop implicitly compares to the current value of $. (that's part of the description that I didn't quote; see the manual). On lines 5 through 9, it yields a true value (experiment shows that it's a number, but the documentation doesn't say so). On line 10, it yields a number with "E0" appended to it -- i.e., it's in exponential notation, but with the same value it would have without the "E0".
The point of the "E0" tweak is to let you detect whether you're in a specified range and to flag the last line in the range for special treatment. Without the "E0", you wouldn't be able to treat the final match specially.
An example:
#!/usr/bin/perl
use strict;
use warnings;
while (<>) {
my $dotdot = 2..4;
print "On line $., 2..4 yields \"$dotdot\"\n";
}
Given 5 lines of input, this prints:
On line 1, 2..4 yields ""
On line 2, 2..4 yields "1"
On line 3, 2..4 yields "2"
On line 4, 2..4 yields "3E0"
On line 5, 2..4 yields ""
This lets you detect whether a line is inside or outside the range and when it's the last line in the range.
But scalar .. is probably more commonly used just for its boolean result, often in one-liners; for example, perl -ne 'print if 2..4' will print lines 2, 3, and 4 of whatever input you give it. It's deliberately similar to sed -n '2,4p'.
The answer can be found by consulting perldoc's perlop page:
Binary ".." is the range operator, which is really two different operators depending on the context. In list context, it returns a list of values counting (up by ones) from the left value to the right value...
This is the familiar usage, which is invoked by print "a" .. "c"; because arguments to functions are evaluated in list context. (If they were evaluated in scalar context, then print #list would print the size of #list, which is almost definitely not what people usually want.)
In scalar context, ".." returns a boolean value. The operator is bistable, like a flip-flop, and emulates the line-range (comma) operator of sed, awk, and various editors. Each ".." operator maintains its own boolean state, even across calls to a subroutine that contains it. It is false as long as its left operand is false. Once the left operand is true, the range operator stays true until the right operand is true, AFTER which the range operator becomes false again. It doesn't become false till the next time the range operator is evaluated. It can test the right operand and become false on the same evaluation it became true (as in awk), but it still returns true once. If you don't want it to test the right operand until the next evaluation, as in sed, just use three dots ("...") instead of two. In all other regards, "..." behaves just like ".." does.
It goes into further detail, but the bolded sections are the important parts to understanding how the operator works. Scalar context is forced by $a =, i.e. assignment to a scalar lvalue. If you did #a =, it would print what you expect.
Note that "a" .. "b" doesn't produce the string "abc", it produces the list ("a", "b", "c"). You will get similar results if you used the list (though the value printed when the list is forced into scalar context will differ).

Why does !1 give me nothing in Perl?

This is strange.
The following:
$sum = !0;
print $sum;
prints out 1 as you would expect. But this
$sum = !1;
print $sum;
prints out nothing. Why?
Be careful: what you've written isn't doing what you think it's doing. Remember, perl has no real boolean datatype. It's got scalars, hashes, lists, and references. The way it handles true/false values, then, is contextual. Everything evaluates to "true" in perl except for undefined variables, the empty list, the empty string, and the number 0.
What your code is doing, then, is taking the inverse of a value that evaluates to "false", which can be anything which is not in the list above. By convention and for simplicity's sake, perl returns 1 (though you should not rely on that; it could very well return a list containing a series of random numbers, because that will evaluate to "true" as well.)
A similar thing happens when you ask for the inverse of a value that evaluates to "true." What's actually being printed out is not "nothing," it's the empty string (''), which, as I mentioned, evaluates to "false" in boolean expressions. You can check this:
print "This evaluates to false\n" if( (!1) eq '');
If you're asking for why perl spits out the empty string instead of one of the other "false" values, well, it's probably because perl is made to handle strings and that's a perfectly reasonable string to hand back.
The operators that only return a boolean result will always return 1 for true and a special false value that's "" in string contexts but 0 in numeric contexts.
Here's an addendum to the other great answers you've already gotten.
Not's Not Not
Consider the following code that tests each of Perl's 'not' operators:
#!/usr/bin/perl
use strict;
use warnings;
for( '!1', 'not 1', '~0' ) {
my $value = eval;
my $zero_plus = 0 + $value;
print join "\n",
"\nExpression: $_",
"Value: '$value'",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: '$zero_plus'",
'';
}
print "\nTest addition for a literal null string: ";
print 0+'', "\n";
use Scalar::Util qw(dualvar);
{ # Test a dualvar
my $value = dualvar 0, '';
my $zero_plus = 0+$value;
print join "\n",
"\nExpression: dualvar",
"Value: '$value'",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: '$zero_plus'",
'';
}
Executing it results in the following. Notice the warning message:
Argument "" isn't numeric in addition (+) at test.pl line 21.
Expression: !1
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
Expression: not 1
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
Expression: ~0
Value: '4294967295'
Defined: 1
Length: 10
Plus: 4294967295
Plus Zero: '4294967295'
Test addition for a literal null string: 0
Expression: dualvar
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
From this we learn several things.
The first two items are not all that exciting:
!1 and not 1 behave in basically the same way.
Unsurpisingly, ~1 is different (it's the bitwise not).
Now, the interesting item:
While we do get a warning for line 21 (0+''), there is no warning generated when we add 0+!1.
It Takes Two to Tangle
Something fishy is happening, and that fishiness has to do with special scalar contexts in Perl. In this case, the distinction between numeric and string contexts. And the ability to create a variable that has different values in each context, aka a dual variable.
It looks like !1 returns a dual variable that returns 0 in numeric context and the null string in string context.
The dualvar test at the end shows that a homemade dualvar works the same way as !1.
But It's A Good Thing
Like many Perl features, dual variables seem at first to defy expectations, and can be confusing. However, like those other features, used appropriately they make life much easier.
As far as I know, a dualvar of 0 and '' is the only defined value that will return false in all scalar contexts. So it is a very sensible return value for !1. One could argue that undef is a good false result, but then an uninitialized variable is not distinguishable from a false value. Also, attempts to print or add the results of booleans would then be plagued with unnecessary warnings.
Another famous dualvar is $! or $OS_ERROR if you use English. In numeric form, you get the error code, in string form, the error code is translated for you.
It's Not Nothing, It's Empty, But It's Nought
So in summary, you aren't getting nothing, you aren't getting an empty string, and you aren't getting zero.
You are getting a variable that is both an empty string and 0 at the same time.
The ! operator does boolean operations. "" (The empty string) is just as false as 0 is. 1 is a convenient true value. ! shouldn't be relied on to do anything other than produce some true/false value. Relying on the exact value beyond that is dangerous and may change between versions of Perl.
See perldoc perlsyn:
Truth and Falsehood
The number 0, the strings '0' and '' ,
the empty list () , and undef are all
false in a boolean context. All other
values are true. Negation of a true
value by ! or not returns a special
false value. When evaluated as a
string it is treated as '' , but as a
number, it is treated as 0.
There, if you print the value as a number, you will get 0 rather than the empty string:
printf "%d\n", $_ for map { !$_ } (1, 0);
or
print 0 + $_, "\n" for map { !$_ } (1, 0);
Compare those to
printf "%s\n", $_ for map { !$_ } (1, 0);
and
print $_, "\n" for map { !$_ } (1, 0);

How do I get the length of a string in Perl?

What is the Perl equivalent of strlen()?
length($string)
perldoc -f length
length EXPR
length Returns the length in characters of the value of EXPR. If EXPR is
omitted, returns length of $_. Note that this cannot be used on an
entire array or hash to find out how many elements these have. For
that, use "scalar #array" and "scalar keys %hash" respectively.
Note the characters: if the EXPR is in Unicode, you will get the num-
ber of characters, not the number of bytes. To get the length in
bytes, use "do { use bytes; length(EXPR) }", see bytes.
Although 'length()' is the correct answer that should be used in any sane code, Abigail's length horror should be mentioned, if only for the sake of Perl lore.
Basically, the trick consists of using the return value of the catch-all transliteration operator:
print "foo" =~ y===c; # prints 3
y///c replaces all characters with themselves (thanks to the complement option 'c'), and returns the number of character replaced (so, effectively, the length of the string).
length($string)
The length() function:
$string ='String Name';
$size=length($string);
You shouldn't use this, since length($string) is simpler and more readable, but I came across some of these while looking through code and was confused, so in case anyone else does, these also get the length of a string:
my $length = map $_, $str =~ /(.)/gs;
my $length = () = $str =~ /(.)/gs;
my $length = split '', $str;
The first two work by using the global flag to match each character in the string, then using the returned list of matches in a scalar context to get the number of characters. The third works similarly by splitting on each character instead of regex-matching and using the resulting list in scalar context