在可可中生成一个随机的字母数字字符串


145

我想调用一个方法,传递它的长度,并让它生成一个随机的字母数字字符串。

是否有实用程序库可能包含许多此类功能?

Answers:


312

这是一个快速而肮脏的实现。尚未测试。

NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

-(NSString *) randomStringWithLength: (int) len {

    NSMutableString *randomString = [NSMutableString stringWithCapacity: len];

    for (int i=0; i<len; i++) {
         [randomString appendFormat: @"%C", [letters characterAtIndex: arc4random_uniform([letters length])]];
    }

    return randomString;
}

1
genRandStringLength应该只返回randomString。没有理由分配和初始化(而不是自动释放!)一个全新的字符串。
kevingessner 2010年

5
只是要把它放在那里。当简单数组可以正常工作时,没有理由使用NSStringfor 。实际上,在我看来,使用不如仅仅简单。Foundation类确实很有帮助,但是对于最简单的事情,它们可以使我们的代码模糊化而不是对其进行增强。letterschar[letters characterAtIndex:(rand() % [letters length])]letters[rand() % strlen(letters)]
乔纳森·斯特林

3
您可能需要%C而不是%c,因为它会characterAtIndex:unichar
2011年

8
当数组长度不是2的幂时,使用arc4random会产生偏差的结果。arc4random_uniform修复了此问题。
jlukanta

9
哦,编译器会警告您精度会下降,因此最好arc4random_uniform((int)[letters length])
强制转换

103

并非完全符合您的要求,但仍然有用:

[[NSProcessInfo processInfo] globallyUniqueString]

样本输出:

450FEA63-2286-4B49-8ACC-9822C7D4356B-1376-00000239A4AC4FD5

2
到目前为止,这是解决该问题的最短,最直接的方法。
adib 2015年

即使其中包含连字符-如果您不必担心,那就太棒了!
fatuhoku 2015年

最好的答案了一大截
Rambatino

非常适合我“在可可中生成随机字母数字字符串”的需求。OP提出的要求并不完全是因为他添加了YAGNI的“传递长度”的要求!
jkoreska 2015年

5
对于大多数用途来说这可能是可以的,但是如果出于安全目的需要一个随机字符串,则不要使用。唯一!=随机。长度是恒定的,使用的字符范围是有限的(0-9,AF,-= 17,而aZ。0-9是62)。此字符串是唯一的但可以预测。
amcc 2015年

67
NSString *alphabet  = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:20];
for (NSUInteger i = 0U; i < 20; i++) {
    u_int32_t r = arc4random() % [alphabet length];
    unichar c = [alphabet characterAtIndex:r];
    [s appendFormat:@"%C", c];
}

13
您是否真的需要查询alphabet每次的时间长度?它是常数,不依赖于循环。
2012年

1
通过生成每个10个字符的1M密码进行测试,效果很好。
NaXir 2014年

1
NSArray缓存其length,不应成为性能瓶颈。
Pascal

我同意。这是一个简单的属性访问。您每次询问时都不会自行计算。
devios1 '16

45

当然,您可以将其缩短:

+(NSString*)generateRandomString:(int)num {
    NSMutableString* string = [NSMutableString stringWithCapacity:num];
    for (int i = 0; i < num; i++) {
        [string appendFormat:@"%C", (unichar)('a' + arc4random_uniform(26))];
    }
    return string;
}

2
为什么为-1?这根本没有错。这就像所有答案中最小,最优化的。
John Riselvato

5
这没什么错。这是一个很好而简洁的解决方案。(我希望SO能够对票证进行评论。)
alvi

最佳解决方案。唯一的评论是,我将其设为静态方法。
安德烈(Andrei Tchijov)

9
唯一的缺点是它不是真正的字母数字,而是小写字母。;-)
PrimaryFeather 2013年

我认为您需要将25更改为26,否则您将永远无法获得“ z”。
马库斯·亚当斯

28

如果您只想将自己限制为十六进制字符,那么最简单的选择是生成一个UUID:

NSString *uuid = [NSUUID UUID].UUIDString;

输出示例:16E3DF0B-87B3-4162-A1A1-E03DB2F59654

如果您希望使用较小的随机字符串,则可以仅获取前8个字符。

这是版本4 UUID,这意味着第3和第4组中的第一个字符不是随机的(它们总是 4和之一89AB)。

字符串中的每个其他字符都是完全随机的,并且数百年来,您每秒可以生成数百万个UUID,而不会多次产生相同的UUID的风险。


1
您可以简单地使用NSString *uuid = [UUID UUID]
orkoden,2014年

@orkoden谢谢,我的代码来自一些iOS 5代码。我将更新答案以使用更新的iOS 6 / OS X 10.8 API。
Abhi Beckert

@AbhiBeckert使用仅前8个字符是否安全,而不会冒相同的前8个字符的风险?
维沙尔·辛格

1
@VishalSingh是的,这很安全,尽管显然您使其越短,发生碰撞的风险就越高。
阿披·贝克特

3
NSString * uuid = [UUID UUID] .UUIDString; 会给您错误“使用未声明的标识符UUID”,因此只需稍作更改即可使用NSString * uuid = [NSUUID UUID] .UUIDString;
阿巴斯·穆拉尼

24

Jeff B答案的类别版本。

NSString + Random.h

#import <Foundation/Foundation.h>

@interface NSString (Random)

+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length;

@end

NSString + Random.m

#import "NSString+Random.h"

 @implementation NSString (Random)

+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length
{ 
    NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];

    for (int i = 0; i < length; i++) {
        [randomString appendFormat:@"%C", [letters characterAtIndex:arc4random() % [letters length]]];
    }

    return randomString;
}

@end

1
这是如何使用类别的一个很好的例子!
ElmerCat 2014年

7

您也可以只生成一个UUID。尽管不是真正随机的,但它们却是复杂且独特的,这使得它们在大多数用途中显得随机。生成一个字符串,然后使用等于传递长度的一系列字符。


对于任何与安全相关的问题,我强烈建议您不要这样做。伪随机性是黑客在渗透系统中使用的最大漏洞之一,因为它们具有可预测性。使用尽可能接近真实的随机数。
Shayne 2013年

5

迅速

func randomStringWithLength(length: Int) -> String {
    let alphabet = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    let upperBound = UInt32(count(alphabet))
    return String((0..<length).map { _ -> Character in
        return alphabet[advance(alphabet.startIndex, Int(arc4random_uniform(upperBound)))]
    })
}

1
简短而甜美。为我工作,但是当我更改字母时,它崩溃了,因为字母长度是硬编码的。我将64个替换为UInt32(count(alphabet))
scootermg 2015年

好。我用硬64计算代替了硬编码upperBound。我upperBound在块外进行计算,因为我认为它的性能更好。
ma11hew28

不能援引“计数”类型的参数列表“(字符串)”使用“alphabet.characters.count”把手
Zaporozhchenko阿列克

返回字母[alphabet.startIndex.advancedBy(Int(arc4random_uniform(upperBound)))
Zaporozhchenko Oleksandr,

4

这是解决问题的另一种方法。您可以使用整数和字符之间的转换,而不是使用准备好的字符串来生成要选择的动态字符列表。它非常精简和快速,但是有更多代码。

int charNumStart = (int) '0';
int charNumEnd = (int) '9';
int charCapitalStart = (int) 'A';
int charCapitalEnd = (int) 'Z';
int charLowerStart = (int) 'a';
int charLowerEnd = (int) 'z';

int amountOfChars = (charNumEnd - charNumStart) + (charCapitalEnd - charCapitalStart) + (charLowerEnd - charLowerStart); // amount of the characters we want.
int firstGap = charCapitalStart - charNumEnd; // there are gaps of random characters between numbers and uppercase letters, so this allows us to skip those.
int secondGap = charLowerStart - charCapitalEnd; // similar to above, but between uppercase and lowercase letters.

// START generates a log to show us which characters we are considering for our UID.
NSMutableString *chars = [NSMutableString stringWithCapacity:amountOfChars];
for (int i = charNumStart; i <= charLowerEnd; i++) {
    if ((i >= charNumStart && i <= charNumEnd) || (i >= charCapitalStart && i <= charCapitalEnd) || (i >= charLowerStart && i <= charLowerEnd)) {
        [chars appendFormat:@"\n%c", (char) i];
    }
}
NSLog(@"chars: %@", chars);
// END log

// Generate a uid of 20 characters that chooses from our desired range.
int uidLength = 20;
NSMutableString *uid = [NSMutableString stringWithCapacity:uidLength];
for (int i = 0; i < uidLength; i++) {
    // Generate a random number within our character range.
    int randomNum = arc4random() % amountOfChars;
    // Add the lowest value number to line this up with a desirable character.
    randomNum += charNumStart;
    // if the number is in the letter range, skip over the characters between the numbers and letters.
    if (randomNum > charNumEnd) {
        randomNum += firstGap;
    }
    // if the number is in the lowercase letter range, skip over the characters between the uppercase and lowercase letters.
    if (randomNum > charCapitalEnd) {
        randomNum += secondGap;
    }
    // append the chosen character.
    [uid appendFormat:@"%c", (char) randomNum];
}
NSLog(@"uid: %@", uid);

// Generate a UID that selects any kind of character, including a lot of punctuation. It's a bit easier to do it this way.
int amountOfAnyCharacters = charLowerEnd - charNumStart; // A new range of characters.
NSMutableString *multiCharUid = [NSMutableString stringWithCapacity:uidLength];
for (int i = 0; i < uidLength; i++) {
    // Generate a random number within our new character range.
    int randomNum = arc4random() % amountOfAnyCharacters;
    // Add the lowest value number to line this up with our range of characters.
    randomNum += charNumStart;
    // append the chosen character.
    [multiCharUid appendFormat:@"%c", (char) randomNum];
}
NSLog(@"multiCharUid: %@", multiCharUid);

当我进行随机字符生成时,我更喜欢直接使用整数并将其强制转换,而不是写出我想从中提取的字符列表。在顶部声明变量将使其与系统更加无关,但是此代码假定数字的值将小于字母,大写字母的值将小于小写字母。


3

Swift中的替代解决方案

func generateString(len: Int) -> String {
    let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let lettersLength = UInt32(countElements(letters))
    let result = (0..<len).map { _ -> String in
        let idx = Int(arc4random_uniform(lettersLength))
        return String(letters[advance(letters.startIndex, idx)])
    }
    return "".join(result)
}

2

除了Melvin给出的良好答案之外,这是我在SWIFT中制作的用于获取随机字符串的函数:

func randomStringOfLength(length:Int)->String{
    var wantedCharacters:NSString="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789"
    var s=NSMutableString(capacity: length)
    for (var i:Int = 0; i < length; i++) {
        let r:UInt32 = arc4random() % UInt32( wantedCharacters.length)
        let c:UniChar = wantedCharacters.characterAtIndex( Int(r) )
        s.appendFormat("%C", c)
    }
    return s
}

这是来自调用的测试结果randomStringOfLength(10)uXa0igA8wm


2

生成具有给定长度的小写字母数字随机字符串:

-(NSString*)randomStringWithLength:(NSUInteger)length
{
    NSMutableString* random = [NSMutableString stringWithCapacity:length];

    for (NSUInteger i=0; i<length; i++)
    {
        char c = '0' + (unichar)arc4random()%36;
        if(c > '9') c += ('a'-'9'-1);
        [random appendFormat:@"%c", c];
    }

    return random;
}

2

在这里和在完成的Swift 4.0中修改了一些想法

extension String
{
    subscript (i: Int) -> Character
    {
        return self[index(startIndex, offsetBy:i)]
    }

    static func Random(length:Int=32, alphabet:String="ABCDEF0123456789") -> String
    {
        let upperBound = UInt32(alphabet.count)
        return String((0..<length).map { _ -> Character in
            return alphabet[Int(arc4random_uniform(upperBound))]
        })
    }
}

用法:

let myHexString = String.Random()
let myLongHexString = String.Random(length:64)
let myLettersString = String.Random(length:32, alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ")

1

如果需要随机的unicode字符串,则可以创建随机的字节,然后使用有效的字节。

    OSStatus sanityCheck = noErr;
    uint8_t * randomBytes = NULL;
    size_t length = 200; // can of course be variable

    randomBytes = malloc( length * sizeof(uint8_t) );
    memset((void *)randomBytes, 0x0, length);

    sanityCheck = SecRandomCopyBytes(kSecRandomDefault, length, randomBytes);

    if (sanityCheck != noErr) NSLog(@"Error generating random bytes, OSStatus == %ld.", sanityCheck);

    NSData* randomData = [[NSData alloc] initWithBytes:(const void *)randomBytes length: length];
    if (randomBytes) free(randomBytes);

    NSString* dataString = [[NSString alloc] initWithCharacters:[randomData bytes] length:[randomData length]];  // create an NSString from the random bytes
    NSData* tempData = [dataString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];             // remove illegal characters from string
    NSString* randomString = [[NSString alloc] initWithData:tempData encoding:NSUTF8StringEncoding];

要获得有效的UTF-8字符串,必须将NSString转换为NSData并返回。请注意,长度不一定是最后创建的NSString的长度。


1

我使用的是简单字母char[]而不是NSString *字母。我将此添加到NSString类别。

static const char __alphabet[] =
    "0123456789"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz";
+ (NSString *)randomString:(int)length
{
    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
    u_int32_t alphabetLength = (u_int32_t)strlen(__alphabet);
    for (int i = 0; i < length; i++) {
        [randomString appendFormat:@"%c", __alphabet[arc4random_uniform(alphabetLength)]];
    }
    return randomString;
}

1
static NSUInteger length = 32;
static NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
NSMutableString * randomString = [NSMutableString stringWithCapacity:length];
for (NSInteger i = 0; i < length; ++i) {
    [randomString appendFormat: @"%C", [letters characterAtIndex:(NSUInteger)arc4random_uniform((u_int32_t)[letters length])]];
}

1

调用方法:


NSString *string = [self stringWithRandomSuffixForFile:@"file.pdf" withLength:4]

方法:


- (NSString *)stringWithRandomSuffixForFile:(NSString *)file withLength:(int)length
{
    NSString *alphabet = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    NSString *fileExtension = [file pathExtension];
    NSString *fileName = [file stringByDeletingPathExtension];
    NSMutableString *randomString = [NSMutableString stringWithFormat:@"%@_", fileName];

    for (int x = 0; x < length; x++) {
        [randomString appendFormat:@"%C", [alphabet characterAtIndex: arc4random_uniform((int)[alphabet length]) % [alphabet length]]];
    }
    [randomString appendFormat:@".%@", fileExtension];

    NSLog(@"## randomString: %@ ##", randomString);
    return randomString;
}

结果:


## randomString: file_Msci.pdf ##
## randomString: file_xshG.pdf ##
## randomString: file_abAD.pdf ##
## randomString: file_HVwV.pdf ##

1

对于Swift 3.0

func randomString(_ length: Int) -> String {

    let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let len = UInt32(letters.length)

    var randomString = ""

    for _ in 0 ..< length {
        let rand = arc4random_uniform(len)
        var nextChar = letters.character(at: Int(rand))
        randomString += NSString(characters: &nextChar, length: 1) as String
    }

    return randomString
}

0
#define ASCII_START_NUMERS 0x30
#define ASCII_END_NUMERS 0x39
#define ASCII_START_LETTERS_A 0x41
#define ASCII_END_LETTERS_Z 0x5A
#define ASCII_START_LETTERS_a 0x61
#define ASCII_END_LETTERS_z 0x5A

-(NSString *)getRandomString:(int)length {
    NSMutableString *result = [[NSMutableString alloc]init];
    while (result.length != length) {
        NSMutableData* data = [NSMutableData dataWithLength:1];
        SecRandomCopyBytes(kSecRandomDefault, 1, [data mutableBytes]);
        Byte currentChar = 0;
        [data getBytes:&currentChar length:1];
        NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        if (currentChar > ASCII_START_NUMERS && currentChar < ASCII_END_NUMERS) { // 0 to 0
            [result appendString:s];
            continue;
        }
        if (currentChar > ASCII_START_LETTERS_A && currentChar < ASCII_END_LETTERS_Z) { // 0 to 0
            [result appendString:s];
            continue;
        }
        if (currentChar > ASCII_START_LETTERS_a && currentChar < ASCII_END_LETTERS_z) { // 0 to 0
            [result appendString:s];
            continue;
        }
    }
    return result;
}

0

修改keithyip的答案:

+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length
{
    static NSString * const letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        srand(time(NULL));
    });

    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];

    for (int i = 0; i < length; i++) {
        [randomString appendFormat:@"%C", [letters characterAtIndex:arc4random() % [letters length]]];
    }

    return randomString;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.