NSString

时间:2016-09-07 22:47:49

标签: objective-c string random

我正试图找出解决问题的最佳方法。我有一个基本上随机的字母数字字符串,我正在动态生成:

NSString *string = @"e04325ca24cf20ac6bd6ebf73c376b20ac57192dad83b22602264e92dac076611b51142ae12d2d92022eb2c77f";

你可以看到没有特殊字符,只有数字和字母,所有字母都是小写字母。将此字符串中的所有字母更改为大写很容易:

[string capitalizedString];

困难的部分是我想在这个字符串中大写随机字符,而不是全部。例如,这可能是一次执行时的输出:

E04325cA24CF20ac6bD6eBF73C376b20Ac57192DAD83b22602264e92daC076611b51142AE12D2D92022Eb2C77F

这可能是另一个的输出,因为它是随机的:

e04325ca24cf20aC6bd6eBF73C376B20Ac57192DAd83b22602264E92dAC076611B51142AE12D2d92022EB2c77f

如果它使这更容易,让我们说我也有两个变量:

int charsToUppercase = 12;//hardcoded value for how many characters to uppercase here
int totalChars = 90;//total string length

在这种情况下,这将意味着该字符串中90个中的12个随机字符将被大写。到目前为止我已经想到的是我可以相对容易地遍历字符串中的每个字符:

NSUInteger len = [string length];
unichar buffer[len+1];

[string getCharacters:buffer range:NSMakeRange(0, len)];

NSLog(@"loop through each char");
for(int i = 0; i < len; i++) {
    NSLog(@"%C", buffer[i]);
}

仍然坚持在此循环中选择随机字符为大写,因此并非所有字符都是大写的。我猜测for循环中的条件可以很好地完成这个技巧,因为它足够随机。

1 个答案:

答案 0 :(得分:1)

这是一种方式,不是特别关注效率,但也不是愚蠢的效率:在原始字符串中创建一个数组字符,建立一个索引,其中一行是字母......

NSString *string = @"e04325ca24cf20ac6bd6ebf73c376b20ac57192dad83b22602264e92dac076611b51142ae12d2d92022eb2c77f";
NSMutableArray *chars = [@[] mutableCopy];
NSMutableArray *letterIndexes = [@[] mutableCopy];

for (int i=0; i<string.length; i++) {
    unichar ch = [string characterAtIndex:i];
    // add each char as a string to a chars collection
    [chars addObject:[NSString stringWithFormat:@"%c", ch]];
    // record the index of letters
    if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {
        [letterIndexes addObject:@(i)];
    }
}

现在,从letterIndexes中随机选择(在我们去的时候移除它们)以确定哪些字母应为大写。将该索引处的chars数组的成员转换为大写...

int charsToUppercase = 12;

for (int i=0; i<charsToUppercase && letterIndexes.count; i++) {
    NSInteger randomLetterIndex = arc4random_uniform((u_int32_t)(letterIndexes.count));
    NSInteger indexToUpdate = [letterIndexes[randomLetterIndex] intValue];
    [letterIndexes removeObjectAtIndex:randomLetterIndex];

    [chars replaceObjectAtIndex:indexToUpdate withObject:[chars[indexToUpdate] uppercaseString]];
}

请注意&&letterIndexes.count的检查。这可以防止charsToUppercase超过chars数量的情况。转换为大写的上限是原始字符串中的所有字母。

现在剩下的就是将chars数组加入字符串......

NSString *result = [chars componentsJoinedByString:@""];
NSLog(@"%@", result);

编辑在OP评论中查看讨论,您可以使用大写更改作为输入而不是charsToUppercase输入参数。这会将这个想法压缩成一个循环,只需要少一点的数据转换......

NSString *string = @"e04325ca24cf20ac6bd6ebf73c376b20ac57192dad83b22602264e92dac076611b51142ae12d2d92022eb2c77f";

float upperCaseProbability = 0.5;
NSMutableString *result = [@"" mutableCopy];

for (int i=0; i<string.length; i++) {
    NSString *chString = [string substringWithRange:NSMakeRange(i, 1)];
    BOOL toUppercase = arc4random_uniform(1000) / 1000.0 < upperCaseProbability;

    if (toUppercase) {
        chString = [chString uppercaseString];
    }
    [result appendString:chString];
}
NSLog(@"%@", result);

然而,这假定任何字符的给定大写概率,而不是任何字母,因此它不会导致预定数量的字母改变大小写。