Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Base 62 conversion in Objective-C

Tags:

I spent much too much time trying to find an implementation for base 62 conversion for Objective-C. I am sure this is a terrible example and there must be an elegant, super-efficient way to do this, but this works, please edit or answer to improve it! But I wanted to help people searching for this to have something that will work. There doesn't appear to be anything specific to be found for an Objective-C implementation.

@implementation Base62Converter  +(int)decode:(NSString*)string {     int num = 0;     NSString * alphabet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";      for (int i = 0, len = [string length]; i < len; i++)     {         NSRange range = [alphabet rangeOfString:[string substringWithRange:NSMakeRange(i,1)]];         num = num * 62 + range.location;     }      return num; }  +(NSString*)encode:(int)num {     NSString * alphabet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";     NSMutableString * precursor = [NSMutableString stringWithCapacity:3];      while (num > 0)     {         [precursor appendString:[alphabet substringWithRange:NSMakeRange( num % 62, 1 )]];         num /= 62;     }      // http://stackoverflow.com/questions/6720191/reverse-nsstring-text     NSMutableString *reversedString = [NSMutableString stringWithCapacity:[precursor length]];      [precursor enumerateSubstringsInRange:NSMakeRange(0,[precursor length])                              options:(NSStringEnumerationReverse |NSStringEnumerationByComposedCharacterSequences)                           usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {                               [reversedString appendString:substring];                           }];     return reversedString; }  @end 
like image 609
ToddB Avatar asked Feb 08 '13 19:02

ToddB


1 Answers

Your code is fine. If anything, make it more generic. Here is a recursive version for any base (same code):

#import <Foundation/Foundation.h>  @interface BaseConversion : NSObject +(NSString*) formatNumber:(NSUInteger)n toBase:(NSUInteger)base; +(NSString*) formatNumber:(NSUInteger)n usingAlphabet:(NSString*)alphabet; @end  @implementation BaseConversion  // Uses the alphabet length as base. +(NSString*) formatNumber:(NSUInteger)n usingAlphabet:(NSString*)alphabet {     NSUInteger base = [alphabet length];     if (n<base){         // direct conversion         NSRange range = NSMakeRange(n, 1);         return [alphabet substringWithRange:range];     } else {         return [NSString stringWithFormat:@"%@%@",                  // Get the number minus the last digit and do a recursive call.                 // Note that division between integer drops the decimals, eg: 769/10 = 76                 [self formatNumber:n/base usingAlphabet:alphabet],                  // Get the last digit and perform direct conversion with the result.                 [alphabet substringWithRange:NSMakeRange(n%base, 1)]];     } }  +(NSString*) formatNumber:(NSUInteger)n toBase:(NSUInteger)base  {     NSString *alphabet = @"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 62 digits     NSAssert([alphabet length]>=base,@"Not enough characters. Use base %ld or lower.",(unsigned long)[alphabet length]);     return [self formatNumber:n usingAlphabet:[alphabet substringWithRange:NSMakeRange (0, base)]]; }  @end  int main(int argc, char *argv[]) {     @autoreleasepool {         NSLog(@"%@",[BaseConversion formatNumber:3735928559 toBase:16]); // deadbeef         return EXIT_SUCCESS;     } } 

A Swift 3 version: https://gist.github.com/j4n0/056475333d0ddfe963ac5dc44fa53bf2

like image 134
Jano Avatar answered Sep 18 '22 12:09

Jano