24

我花了太多时间试图为 Objective-C 找到 base 62 转换的实现。我确信这是一个糟糕的例子,必须有一种优雅、超高效的方法来做到这一点,但这有效,请编辑或回答以改进它!但我想帮助那些寻找这个的人有一些有用的东西。似乎没有针对 Objective-C 实现找到任何特定的东西。

@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
4

2 回答 2

16

你的代码很好。如果有的话,让它更通用。这是任何基础的递归版本(相同的代码):

#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;
    }
}

Swift 3 版本:https ://gist.github.com/j4n0/056475333d0ddfe963ac5dc44fa53bf2

于 2013-02-08T20:03:27.147 回答
6

encode您可以以不需要反转最终字符串的方式改进您的方法:

+ (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;
}

当然,这也可以推广到任意基础或字母,正如@Jano 在他的回答中所建议的那样。

请注意,此方法(以及您的原始encode方法)返回一个空字符串 for num = 0,因此您可能需要单独考虑这种情况(或仅替换while (num > 0) { ... }do { ... } while (num > 0).


为了提高效率,可以NSString完全避免所有中间对象,并使用纯 C 字符串:

+ (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];
}
于 2013-02-08T22:06:20.930 回答