Just a reminder:
Syntax of for:
for (init something;test;do something) {
stuff
}
In the first for, you don't init anything, have a long test, and do nothing, so you could also write the first line as a while-loop:
while ($_?$,:(${_} = q...q,.,.qq,$=,^q.$..$= => $_=q,.,.chr ord)) {
Here you first check if $_ is defined. If it is, you return $, which defaults to undef, thus ending the loop. If $_ is not defined (the default), we enter this statement:
${_} = q...q,.,.qq,$=,^q.$..$= => $_=q,.,.chr ord
Now, lets de-obfuscate:
${_} is the same as $_, the curly braces beeing used like in @{$arrayref}
q.. . q,., . qq,S=, ^ q.$. . $= => $_=q,., . chr ord
looks like
'' . '.' . "$=" ^ '$' . $= , $_= '.' . chr ord
when using normal quotes.
This is a list consisting of two items:
'' . '.' . "$=" ^ '$' . $=
and
$_= '.' . chr ord
Lets look at the first part:
'' . '.' . "$=" ^ '$' . $=
This uses ^ as XOR, which somehow means (i'm not tha good at bitwise stuff)
that each bit on the left of ^ gets XOR'ed with each bit on the right, so:
'.$=' ^ '$60'
(where is the 60 coming from? $= or $FORMAT_LINES_PER_PAGE defaults to 60)
which yields the linebrake used in the cascade.
Now, the second part:
$_= '.' . chr ord
This is very intuitive way to write
$_= '.'.$_
ord converts the contents of $_ into the numeric ascii value. Those values then get passed to chr, wich converts numeric asscii values to the corresponding character.
Adding the two parts together, we now have:
($_="\n",$_='.'.$_;)
Which can be further simplified to:
($_=".\n")
So the whole first line looks now like
for(;$_ ? undef : ($_=",\n") {
for(s .. Just another perl hacker.) {
Here you use a . as a regex-separator, so this looks like
for(s//Just another perl hacker/) {
which substitutes the first empty string in $_ with 'Just another perl hacker' and therefor is the same as
s//Just another perl hacker/;
for(;s;.;;;print){ }
remebering the for-syntax, you here again intialise nothing.
The continuination-test looks de-obfuscated like s/.//
which a) removes the first char of $_ (thus causing the cascading effect)
and b) returns undef if $_ is empty, stopping the for-loop
and instead of incrementing a counter (which is usually done here), you just print $_.
The loop itself does nothing;
So:
while (s/.//) {
print $_;
}
We end up with:
while($_ ? undef : ($_=".\n")) {
s//Just another perl hacker/;
while (s/.//) {
print;
}
}
Now lets de-obfuscate the algorithm
The stuff inside the main for-loop is quite easey:
Put "Just another perl hacker" into $_, chop of the first char and print it.
The interesting stuff happens in the definintion of the first while loop
If $_ is defined, return undef. As $_ is not defined by default, in the first run, do the other part if the ? : statement, which sets $_ to "\n."
Now we enter the code in the while-loop, that adds "Just another perl hacker" in front of $_ and than prints the cascade.
That's it (I think ...) | [reply] |
Very nice. :) You almost got it all. However,
$_= '.' . chr ord
is not exactly the same thing as
$_= '.'.$_
Consider this:
${_} = q...q,.,.qq,$=,^q.$..$=;
print ord() . "," foreach(split//);
and then try to replace like this:
for(;$_?$,:(${_} = q...q,.,.qq,$=,^q.$..$= => $_=q,.,.$_ );) {
It destroys the output (or should, at least). This is because ord returns the value of the first character in the string it is fed. There is a difference. If you replace all the way down to $_="\n" then it works again, of course. :)
For more clarity,
for(s//Just another perl hacker/) {
is really
foreach(s//Just another perl hacker/) {
- although they are interchangeable syntax-wise in perl.
I don't know if you used it, but sadly deparsing gives a lot away. What I do think is funny is that deparsing translates one for to while, one to foreach and leaves the last as a for:
while ($_ ? $, : ($_ = '.' . "$=" ^ '$' . $=, $_ = '.' . chr(ord $_)))
+ {
foreach $_ (s// Just another perl hacker/) {
();
}
for (; s/.//; print $_) {
();
}
}
Then again, I guess I am easily amused.
I like your initial reminder too - that was exactly what this was "about" - abusing the for construct, which is also a bit special in perl. :)
And oh, there is one more stripping possible to do - to get to approximately where I started (using your example):
$_=".\n";
s//Just another perl hacker/;
while (s/.//) {
print;
}
Neither of the for loops has any real reason to be nested into any other - it is really just three separate lines of code.
Thank you for taking the time - it is appreciated. :)
You have moved into a dark place.
It is pitch black. You are likely to be eaten by a grue. | [reply] [d/l] [select] |
| [reply] |