Base 62 conversion in Objective-C Base 62 conversion in Objective-C ios ios

Base 62 conversion in Objective-C


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)]];}@endint 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


You could improve your encode method in such a way that reversing the final string is not necessary:

+ (NSString *)encode:(NSUInteger)num{    NSString *alphabet = @"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";    NSUInteger base = [alphabet length];    NSMutableString *result = [NSMutableString string];    while (num > 0) {        NSString *digit = [alphabet substringWithRange:NSMakeRange(num % base, 1)];        [result insertString:digit atIndex:0];        num /= base;    }    return result;}

Of course, this could also be generalized for arbitrary bases or alphabets, as suggested by @Jano in his answer.

Note that this method (as well as your original encode method) returns an empty string for num = 0, so you might want to consider this case separately (or just replace while (num > 0) { ... } by do { ... } while (num > 0).


For more efficiency, one could avoid all intermediate NSString objects altogether, and work with plain C strings:

+ (NSString *)encode:(NSUInteger)num{    static const char *alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";    NSUInteger base = 62;    char result[20]; // sufficient room to encode 2^64 in Base-62    char *p = result + sizeof(result);    *--p = 0; // NULL termination    while (num > 0) {        *--p = alphabet[num % base];        num /= base;    }    return [NSString stringWithUTF8String:p];}