From: MenTaLguY Date: 2008-03-27T06:33:27+09:00 Subject: Re: Encode as alphanumeric On Thu, 27 Mar 2008 05:44:12 +0900, Trans wrote: > On Mar 26, 4:27 pm, MenTaLguY wrote: >> On Thu, 27 Mar 2008 05:13:23 +0900, Trans wrote: >> > I need to take an arbitrary byte string and encode it as alphanumeric >> > (and decode it back again). Any pointers on a easy way to do this? >> >> What sort of encoding do you have in mind? Hexadecimal? Base64? > > I'm using a two-way encryption algorithm to create a registration key. > The encryption algorithm produces an arbitrary byte string. I need to > encode that into something I can give to a end-user, ie. an > alphanumeric string. > > Base64 is close but not quite [a-zA-Z0-9]. I see. Base 62 then? The most direct way is to get things as a bignum and then convert bases using divmod. DIGIT_CHARS = ["0".."9", "a".."z", "A".."Z"].map { |r| r.to_a }.flatten BASE = DIGIT_CHARS.size DIGIT_VALUES = Hash[*(0...BASE).map { |i| [ DIGIT_CHARS[i], i ] }.flatten] def convert_base(digits, from_base, to_base) bignum = 0 digits.each { |digit| bignum = bignum * from_base + digit } converted = [] until bignum.zero? bignum, digit = bignum.divmod to_base converted.push digit end converted.reverse end def encode(byte_string) convert_base(byte_string.unpack("C*"), 256, BASE).map { |d| DIGIT_CHARS[d] }.join('') end def decode(encoded) convert_base(encoded.split('').map { |c| DIGIT_VALUES[c] }, BASE, 256).pack("C*") end There are more efficient ways of accomplishing this, of course. Note that with this implementation, you'd probably want to zero-fill to whatever standard number of characters and bytes you're using, and of course a key of all zeroes will result in an empty string. As a usability thing, I'd also suggest non-uniformly adding dashes or spaces in standard places to the encoded form, to help users visually "chunk" the keys if they ever might have to type them in. -mental