> That's one convoluted JAPH! Thanks.
> I like to pick through admirable JAPH's like this in an > attempt to learn more Perl idiosyncrasies [...] > Anyone care to explain what's going on? How about I tell you how I created it, which I think makes it easier to see what's going on. Every JAPH starts out with a small idea on some transormation of the phrase "Just Another Perl Hacker". I noticed there are repeated letters in that phrase, so I decided to collapse the phrase down to just the unique letters and then rebuild the phrase by indexing them. # Reduce to unique characters $japh = 'Just another Perl hacker'; $letter{$_}++ foreach split//, $japh; print join "", sort keys %letter; So now I'm working with the string " JPacehklnorstu". But that string doesn't have to be in any particular order, so it's off to the Internet Anagram Server (http://www.wordsmith.org/anagram/) to make things interesting. There are lots of funny results, and I ended up making a few different versions of the JAPH with them. The one you saw was "steal Porch Junk". So now, I just create a list of indices to extract the proper phrase back out. I could simply use the following: @indices = (12,13,0,1,5,3,14,7,1,10,2,8,5,6,2,8,4,5,10,3,9,15,2,8); But that would be boring. And take up quite a bit of space. I noticed that the range is 0..15 or one nybble (half a byte). I could pack all 24 indices in just 12 bytes! I decided to represent the bytes as hex characters: # pack 'em into bytes. while (@indices) { $byte = (shift(@indices)<<4)|shift(@indices); printf('%x',$byte); } So now I'm working with the string "cd0153e71a28562845a39f28". To extract the indices, I just have to use hex() on each character in that string. So now, let's put together a first cut at the JAPH, using the techniques above: $_="steal Porch Junk"; @_=split //; # put the letters in @_ $_="cd0153e71a28562845a39f28"; # put the indices in $_ s/(.)/$_[hex($1)]/ge; # replace each index with its letter print; # print it out Now the fun part... let's obfuscate it a bit. Adding another "e" to the regex is low-hanging fruit. We just assemble the '$_[hex($1)]' part via concatenated strings: s/(.)/'$_[' . 'hex' . '($1)]'/gee; I don't like the quotes. Too obvious. Lets change them to q() but use '.' instead of the parens (anyone who gets confused by this needs to read perldoc perlop): s/(.)/q.$_[. . q.hex. . q.($1)]./gee; Looking better, but that 'hex' stands out like a sore thumb. Noticing that the "h" and "e" are in our letter list (@_), I decide to assemble the 'hex', which is just a string at this point, from those letters ("h" = $_[10], "e" = $_[2]), leaving the 'x': s/(.)/q.$_[. . $_[10] . $_[2] . q.x. . q.($1)]./gee Better. Now let's get rid of the quotes from the rest of the JAPH too, using q.. and q== $_=q;steal Porch Junk;;split //; $_=q=cd0153e71a28562845a39f28=; s/(.)/q.$_[. . $_[10] . $_[2] . q.x. . q.($1)]./gee; print; Now let's break up that hex string in the second line. I see it has three "28"'s, so we can do a substitution. What should we replace it with? The string "s/" is about as diabolical as any. ";q" would have been a good one too. I chose the former. In our y// (or y;; to be tricky) lets also replace the "a"'s with ";". We'll also insert a newline, which we take back out with a s/\n//; $_=q;steal Porch Junk;;split//;$_=q=cd0153e71; s/56s/45;39fs/=; y;\;s/;a28;; s;\n;;; s/(.)/q.$_[. . $_[10] . $_[2] . q.x. . q.($1)]./gee; print; Now let's smash it up a bit: $_=q;steal Porch Junk;;split//;$_=q=cd0153e71; s/56s/45;39fs/=;y;\;s/;a28;;s;\n;;; s/(.)/q.$_[..$_[10].$_[2].q.x..q.($1)]./gee;print; Looking kinda JAPHy now, isn't it? There's a few more things we can do. The y operator can take extra chars at the end without consequence. We'll add another decoy 's/'. In the first substitution, let's replace '\n' with '$/'. $_=q;steal Porch Junk;;split//;$_=q=cd0153e71; s/56s/45;39fs/=;y;\;s/;a28s/;;s;$/;;; s((.))/q.$_[..$_[10].$_[2].q.x..q.($1)]./gee;print; Now, let's work on the substitution again. We can split it between lines, and change s/// to s()//. Also we can change the ';' before print to a '/', which is interpreted as a divide, but will still evaluate the 'print' with a warning under -w which we don't care about. $_=q;steal Porch Junk;;split//;$_=q=cd0153e71; s/56s/45;39fs/=;y;\;s/;a28s/;;s;$/;;;s((.))/ q.$_[..$_[10].$_[2].q.x..q.($1)]./gee/print; More stuff: Let's insert some ';' where they won't make a difference, and remove one from the end. Then I want to pad the last line by 2 chars because I like to make the lines equal length. We can add $. (which contains nothing outside a loop) to the substitution string. $_=q;steal Porch Junk;;split//;$_=q=cd0153e71; s/56s/45;39fs/=;y;\;s/;a28s/;;;s;$/;;;s((.))/; q.$_[.$..$_[10].$_[2].q.x..q.($1)]./gee/print; More can always be done, but at this point it looks good enough for me. Hope you found this interesting. -- Mark Thomas [EMAIL PROTECTED] Internet Systems Architect DigitalNet, Inc. $_=q;steal Porch Junk;;split//;$_=q=cd0153e71; s/56s/45;39fs/=;y;\;s/;a28s/;;;s;$/;;;s((.))/; q.$_[..$..$_[10].$_[2].q.x..q.($1)]./gee/print _______________________________________________ Perl-Win32-Users mailing list [EMAIL PROTECTED] To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs