Base-64 encoding--Just for the fun of it!

Discussion in 'Ruby' started by Aaron D. Gifford, Mar 5, 2010.

  1. Yes, there's always:

    require 'base64'
    Base64::encoe64(data)

    But now and then it's fun to write one's own base64 encoder just for
    the fun of it.

    What I want to ask is this: How short can one get a function
    definition that takes a string as input and returns a base-64
    (MIME64-style, except for NO newlines/linefeeds--output is all one
    giant line of encoded text in the character set 'A' to 'Z', 'a' to
    'z', '0' to '9', '+', and '/')?

    The shortest I've got it down to is 276 characters. WARNING: My email
    client is gonna line-break this and mess it up. Just remove the
    whitespace.)

    def e(s);c=('A'..'Z').to_a.join+('a'..'z').to_a.join+'0123456789+/';(t=s.unpack('C*').inject([0,'',0]){|a,v|a[0]==0?[2,a[1]+c[v>>2,1],v*16&48]:a[0]==2?[4,a[1]+c[v>>4|a[2],1],v*4&60]:[0,a[1]+c[v>>6|a[2],1]+c[v&63,
    1],0]})[1]+(t[0]==0?'':t[0]==2?c[t[2],1]+'==':c[t[2],1]+'=');end

    If the above is too corrupted, I stuck it on my personal web site:
    http://www.aarongifford.com/base64.rb.txt

    The 276-character encoder works in Ruby 1.9.1 and Ruby 1.8.7 and
    super-simplistic tests comparing results against the Base64 encoder
    appear to work (as long as you strip out line breaks Base64 includes).

    I'd love to hear suggestions to squeeze a few more characters out of it.

    Ideas? Suggestions?

    Having a bit too much fun fiddling with Ruby,
    Aaron out.
    Aaron D. Gifford, Mar 5, 2010
    #1
    1. Advertising

  2. This morning I realized I could shave off 3 characters by eliminating
    one .join by adding () and converting + to | in the c= initialization.

    Also, for Ruby 1.9 only, one can save 8 more characters since string
    slices return 1-character strings in 1.9 instead of integers.

    I updated http://www.aarongifford.com/base64.rb.txt so it now has the
    original and the two improvements. And it adds a random data test on
    Unix-based hosts supporting reading random data from /dev/urandom

    Oh, I should add that performance is abysmal, but that obviously
    wasn't the goal. *chuckle*

    Aaron out.
    Aaron D. Gifford, Mar 5, 2010
    #2
    1. Advertising

  3. Aaron D. Gifford wrote:
    >(...)
    > The shortest I've got it down to is 276 characters. WARNING: My email
    > client is gonna line-break this and mess it up. Just remove the
    > whitespace.)
    >
    > def
    > e(s);c=('A'..'Z').to_a.join+('a'..'z').to_a.join+'0123456789+/';(t=s.unpack('C*').inject([0,'',0]){|a,v|a[0]==0?[2,a[1]+c[v>>2,1],v*16&48]:a[0]==2?[4,a[1]+c[v>>4|a[2],1],v*4&60]:[0,a[1]+c[v>>6|a[2],1]+c[v&63,
    > 1],0]})[1]+(t[0]==0?'':t[0]==2?c[t[2],1]+'==':c[t[2],1]+'=');end
    >(...)
    > I'd love to hear suggestions to squeeze a few more characters out of it.
    >
    > Ideas? Suggestions?
    >
    > Having a bit too much fun fiddling with Ruby,
    > Aaron out.


    Heh, in ruby 1.9 you can do:

    c=(65..122).to_a.join(&:chr)+'0123456789+/'

    instead of
    c=(('A'..'Z').to_a|('a'..'z').to_a).join+'0123456789+/'

    hth,

    Siep
    --
    Posted via http://www.ruby-forum.com/.
    Siep Korteling, Mar 5, 2010
    #3
  4. Aaron D. Gifford

    Intransition Guest

    On Mar 5, 1:11=A0am, "Aaron D. Gifford" <> wrote:
    > The 276-character encoder works in Ruby 1.9.1 and Ruby 1.8.7 and
    > super-simplistic tests comparing results against the Base64 encoder
    > appear to work (as long as you strip out line breaks Base64 includes).
    >
    > I'd love to hear suggestions to squeeze a few more characters out of it.
    >
    > Ideas? =A0Suggestions?


    While lacking in the joy of code golf you may still be interested to
    know about <a href=3D"http://rubyworks.github.com/radix">Radix</a>
    Intransition, Mar 5, 2010
    #4
  5. Thomas Sawyer wrote:
    > On Mar 5, 1:11�am, "Aaron D. Gifford" <> wrote:
    >> The 276-character encoder works in Ruby 1.9.1 and Ruby 1.8.7 and
    >> super-simplistic tests comparing results against the Base64 encoder
    >> appear to work (as long as you strip out line breaks Base64 includes).
    >>
    >> I'd love to hear suggestions to squeeze a few more characters out of it.
    >>
    >> Ideas? �Suggestions?

    >
    > While lacking in the joy of code golf you may still be interested to
    > know about <a href="http://rubyworks.github.com/radix">Radix</a>


    Yes i am. And please ignore my previous post in this thread, it's
    rubbish.

    Siep
    --
    Posted via http://www.ruby-forum.com/.
    Siep Korteling, Mar 5, 2010
    #5
  6. Aaron D. Gifford

    Kirk Haines Guest

    On Thu, Mar 4, 2010 at 11:11 PM, Aaron D. Gifford <> wrote:

    > The 276-character encoder works in Ruby 1.9.1 and Ruby 1.8.7 and
    > super-simplistic tests comparing results against the Base64 encoder
    > appear to work (as long as you strip out line breaks Base64 includes).


    def e(s);.pack('m');end


    Kirk Haines
    Kirk Haines, Mar 6, 2010
    #6
  7. On Fri, Mar 5, 2010 at 6:55 PM, Kirk Haines <> wrote:
    > def e(s);.pack('m');end


    Thanks for contributing something useful to me. I've always used the
    'base64' module in the past, having overlooked that handy little
    tidbit.

    Aaron out.
    Aaron D. Gifford, Mar 6, 2010
    #7
  8. Aaron D. Gifford

    Guest

    > Yes, there's always:
    >
    > require 'base64'
    > Base64::encoe64(data)


    Actually that's deprecated in 1.9 afaik. Somebody else already pointed out that you can use Array#pack.

    > I'd love to hear suggestions to squeeze a few more characters out of it.


    Yours:
    c=('A'..'Z').to_a.join+('a'..'z').to_a.join+'0123456789+/'

    Mine (1.9 only):
    c=[*?A..?Z,*?a..?z,*?0..?9]*''+'+/'

    That's 23 characters.

    Yours:
    (t=s.unpack('C*').inject([0,'',0]){|a,v|a[0]==0?[2,a[1]+c[v>>2,1],v*16&48]:a[0]==2?[4,a[1]+c[v>>4|a[2],1],v*4&60]:[0,a[1]+c[v>>6|a[2],1]+c[v&63,1],0]})[1]+(t[0]==0?'':t[0]==2?c[t[2],1]+'==':c[t[2],1]+'=')

    Mine:
    (s.unpack("B*")[0]+'0'*((6-s.size*8%6)%6)).scan(/.{6}/).map{|e|c[e.to_i(2)]}*''+'='*((3-s.size%3)%3)

    That's another 104 characters off. So 127 characters less in total :)

    I also did only some very superficial tests, and mine doesn't insert newlines either. Though some clever gsub could do that easily.

    Regards & thanks for the challenge ;-)
    Stefan (aka apeiros)
    --
    Sicherer, schneller und einfacher. Die aktuellen Internet-Browser -
    jetzt kostenlos herunterladen! http://portal.gmx.net/de/go/atbrowser
    , Mar 6, 2010
    #8
  9. On Sat, Mar 6, 2010 at 4:31 PM, <> wrote:
    > Mine (1.9 only):
    > c=[*?A..?Z,*?a..?z,*?0..?9]*''+'+/'
    >
    > That's 23 characters.


    Gorgeous!

    > Mine:
    > (s.unpack("B*")[0]+'0'*((6-s.size*8%6)%6)).scan(/.{6}/).map{|e|c[e.to_i(2)]}*''+'='*((3-s.size%3)%3)


    Beautiful!

    I love learning new things every day, and you've provided plenty for
    me. Thanks for "golf" lessons. *smile*

    Aaron out.
    Aaron D. Gifford, Mar 7, 2010
    #9
  10. On Sat, Mar 6, 2010 at 4:31 PM, <> wrote:
    > (s.unpack("B*")[0]+'0'*((6-s.size*8%6)%6)).scan(/.{6}/).map{|e|c[e.to_i(2)]}*''+'='*((3-s.size%3)%3)


    I notice you could shave off 2 more characters by using the same ?
    character literal for the '0' and the '=' characters:
    (s.unpack("B*")[0]+?0*((6-s.size*8%6)%6)).scan(/.{6}/).map{|e|c[e.to_i(2)]}*''+?=*((3-s.size%3)%3)

    I hope you don't mind, but I added your version to my file at:
    http://www.aarongifford.com/base64.rb.txt

    And I stole your character literal and range expansion (splat) ideas
    to improve my longer algorithm a bit too.

    Thanks again for teaching me about Range expansion inside method calls.

    Aaron out.
    Aaron D. Gifford, Mar 7, 2010
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andy Fish
    Replies:
    65
    Views:
    1,740
    Mabden
    May 18, 2004
  2. CII
    Replies:
    10
    Views:
    1,910
    Keith Thompson
    May 11, 2005
  3. Domingo Fiesta Segura

    Just for fun

    Domingo Fiesta Segura, Oct 8, 2003, in forum: C Programming
    Replies:
    3
    Views:
    330
    Mike Wahler
    Oct 8, 2003
  4. dolphin
    Replies:
    4
    Views:
    317
    Jorgen Grahn
    Aug 25, 2007
  5. er
    Replies:
    2
    Views:
    504
Loading...

Share This Page