在 Cocoa 中生成随机的字母数字字符串

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

有没有一些实用程序库可能包含这些类型的函数?

95753 次浏览

这是一个快速而肮脏的实现,还没有经过测试。

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

您也可以只生成一个 UUID。虽然不是真正的随机,但它们是复杂和独特的,这使得它们在大多数情况下看起来是随机的。生成一个字符串,然后获取与传递的长度相等的字符范围。

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

这里有一个不同的方法来解决它。您可以在整数和字符之间进行强制转换,并生成要选择的字符的动态列表,而不必使用准备好的字符串。它相当精简和快速,但有一点更多的代码。

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);

在进行随机字符生成时,我更喜欢直接处理整数并转换它们,而不是写出我想从中提取的字符列表。在顶部声明变量使它更加独立于系统,但是这段代码假设数字的值比字母低,大写字母的值比小写字母的值低。

Jeff B 答案的分类版本。

NSString + Ranch.h

#import <Foundation/Foundation.h>


@interface NSString (Random)


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


@end

NSString + RRandom. 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

你当然可以简短一点:

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

不完全是你要求的,但仍然有用:

[[NSProcessInfo processInfo] globallyUniqueString]

输出样本:

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

如果您愿意将自己限制为仅使用十六进制字符,那么最简单的选项是生成一个 UUID:

NSString *uuid = [NSUUID UUID].UUIDString;

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

如果你想要一个更小的随机字符串,那么你可以只抓取前8个字符。

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

字符串中的每个其他字符都是完全随机的,您可以在几百年的时间里每秒生成数百万个 UUID,而且不会有两次生成同一个 UUID 的风险。

如果需要随机 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 的长度。

我使用一个简单的 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;
}

要调用的方法:


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

除了 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得到的测试结果

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

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

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

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)
}

斯威夫特

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

为了 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
}

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

这里修改了一些想法,完成了 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")