I'm contemplating about this very little piece of Perl code. I'm already more than a little bit proud of it, but I wondered if the venerated Monks had suggestions to make it even shorter:

print"@ARGV"=~s|.|$_=2+index'temaniowkugrdsXjyqxvpcfzlbh',lc$&;$Q= 1.45*log;$_-=1<<$Q;for($O='';--$Q>0;$_/=2){$O.=chr$_%2+45}"$O "|ger

Try it with some text as command line arguments.

Especially I'm curious about:

Every comment is very much appreciated!

2/15/2016: Corrected two typos!

Replies are listed 'Best First'.
Re: Using the olde times internet
by choroba (Archbishop) on Feb 14, 2016 at 16:20 UTC
    It seems a { is missing after the for(...).

    After adding it, ABCD gets transformed into

    .- ---- ---- ---

    which doesn't seem quite right.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Yes, that's still wrong. In addition to the curly bracket, a slash was also missing. I think this happened while I was writing the post, changing the text and where to break the code a couple of times. Sorry for the confusion, and thanks for pointing it out.

      If you are still having trouble with the lesser used letters (q,x,v,p,c,f,z,l,b,h), then it's probably an encoding problem with the umlauts ,,. If you don't care about them, you can use these lines:

      print"@ARGV"=~s|.|$_=2+index'temaniowkugrdsXjy_q_xv_pcfzlbh',lc$&;$Q= 1.45*log;$_-=1<<$Q;for($O='';--$Q>0;$_/=2){$O.=chr$_%2+45}"$O "|ger

      So, removing the first curly bracket or the slash is obviously not an option to shorten the code :-).

Re: Using the olde times internet
by oiskuu (Hermit) on Feb 16, 2016 at 14:28 UTC

    Here's my alternative take. It's in the form of a filter (reads from standard input).

    #! /usr/bin/perl -p @T{"temnaiogkdwrusXqzycxbjplfvh"=~/./g}=grep!/[^12]/,1..2x4; s/./$T{lc$&} /g;y/12/-./

    Update. A transformed (y/12/21/) mapping moves the X to the string end where it can be dropped; one char saved.

    #! /usr/bin/perl -p @T{"etianmsurwdkgohvflpjbxcyzq"=~/./g}=grep!/[^12]/,1..2x4; s/./$T{lc$&} /g;y/12/.-/

    Update3. Super Search found me this: Morse Code as binary. (And this, this). Here's another variant.

    #! /usr/bin/perl -p s!.!sprintf("%b ",2+index"etianmsurwdkgohvflpjbxcyzq",lc$&)=~s/.//r +=~y/01/.-/r!ge

    As for golfing tricks and links, take a look at the eyepopslikeamosquito user page. There there's a full section of golfing articles.


      • impressed (I'm still trying to get all the tricks, but hey, I've work to do from time to time)
      • a little bit depressed (I thought the idea of arranging the characters in Morse specific order was, well, unique),
      • feeling a little bit cheated on (-p really feels like a cheap trick, doesn't it?)
      And I'm learning tons of stuff. Thanks, guys!

      oiskuus last variant is 87 bytes long:

      s!.!sprintf("%b ",2+index"etianmsurwdkgohvflpjbxcyzq",lc$&)=~s/.//r=~y/01/.-/r!ge

      By assigning to $_, we can scrap the parentheses and the two =~, saving two bytes:

      s!.!$_=sprintf"%b ",2+index"etianmsurwdkgohvflpjbxcyzq",lc$&;s/.//;y/01/.-/r!ge

      Dropping the support for diacritics (only , and where supported anyway) easily saves another five bytes:

      s!.!$_=sprintf"%b ",2+index etianmsurwdkgohvfXlXpjbxcyzq,lc$&;s/.//;y/01/.-/r!ge

      With some shuffling around, we can shave off another byte: (note that this version prints a leading whitespace, while the previous ones printed a trailing whitespace)

      s!.!sprintf" %b",2+index etianmsurwdkgohvfXlXpjbxcyzq,lc$&!ge;s/ ./ /g;y/01/.-/

      Using a regex instead of index saves yet another byte, now down to 78:

      s!.!XetianmsurwdkgohvfXlXpjbxcyzq=~lc$&;sprintf" %b","@+"!ge;s/ ./ /g;y/01/.-/

      Finally, heres a 87 bytes variant that doesnt require the -p flag. Its longer by StackExchanges standard (where -p counts as a single additional byte), but shorter for codegolf.com, where you would have to write the entire 10-byte shebang line.

      print+sprintf("%b ","@+")=~s/.//r=~y/01/.-/rwhile-etianmsurwdkgohvfXlXpjbxcyzq=~lc getc

      I think theres still room for improvement.

        I accidentally posted the above as an Anonymous Monk, and now I cant edit it to fix the glaring typo :/
Re: Using the olde times internet
by mtve (Deacon) on Feb 16, 2016 at 09:48 UTC

    standard trick:


    replace with


    one char shorter

      Very nice. It seems that I can apply it only to $Q, correct?

      print"@ARGV"=~s|.|$_=2+index'temaniowkugrdsXjyqxvpcfzlbh',lc$&;$_ -=1<<($Q=1.45*log);for($O='';--$Q>0;$_/=2){$O.=chr$_%2+45}"$O "|ger

      Does anyone have a list of standard tricks?