Generieren Sie eine zufällige alphanumerische Zeichenfolge in Cocoa


145

Ich möchte eine Methode aufrufen, ihr die Länge übergeben und eine zufällige alphanumerische Zeichenfolge generieren lassen.

Gibt es Dienstprogrammbibliotheken, die möglicherweise eine Reihe solcher Funktionen enthalten?

Antworten:


312

Hier ist eine schnelle und schmutzige Implementierung. Wurde nicht getestet.

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 sollte nur randomString zurückgeben. Es gibt keinen Grund, eine ganz neue Zeichenfolge zuzuweisen und zu initiieren (und nicht automatisch freizugeben!).
Kevingessner

5
Ich werde das hier nur veröffentlichen. Es gibt keinen Grund, ein NSStringzu verwenden, letterswenn ein einfaches charArray gut funktionieren würde. Tatsächlich [letters characterAtIndex:(rand() % [letters length])]scheint mir die Verwendung weniger prägnant zu sein als nur letters[rand() % strlen(letters)]. Die Foundation-Klassen sind wirklich hilfreich, aber im einfachsten Fall können sie dazu dienen, unseren Code zu verschleiern, anstatt ihn zu verbessern.
Jonathan Sterling

3
Sie möchten vielleicht %Cstattdessen %c, weil characterAtIndex:einunichar
user102008

8
Die Verwendung von arc4random würde ein verzerrtes Ergebnis erzeugen, wenn die Array-Länge keine Zweierpotenz ist. arc4random_uniform behebt dies.
Jlukanta

9
Oh, der Compiler würde eine Warnung für den Verlust der Präzision geben, also besser an intarc4random_uniform((int)[letters length])
knshn

103

Nicht genau das, was Sie fragen, aber dennoch nützlich:

[[NSProcessInfo processInfo] globallyUniqueString]

Beispielausgabe:

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

2
Dies ist bei weitem der kürzeste und einfachste Weg, um die Frage zu beantworten.
Adib

Auch wenn es Bindestriche enthält - wenn das kein Problem ist, dann großartig!
Fatuhoku

Beste Antwort von einer Meile
Rambatino

Perfekt für mein Bedürfnis, "eine zufällige alphanumerische Zeichenfolge in Kakao zu generieren". Nicht genau das, was OP verlangt, nur weil er die Anforderung hinzufügt, "die Länge zu übergeben", die YAGNI!
Jkoreska

5
Dies ist wahrscheinlich für die meisten Anwendungen in Ordnung, wird jedoch NICHT verwendet, wenn Sie aus Sicherheitsgründen eine zufällige Zeichenfolge benötigen. Einzigartig! = Zufällig. Die Länge ist konstant, der Bereich der verwendeten Zeichen ist begrenzt (0-9, AF, - = 17, gegenüber 62 für aZ. 0-9). Diese Zeichenfolge ist einzigartig, aber vorhersehbar.
Amcc

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
Müssen Sie wirklich die Länge alphabetjedes Mal abfragen ? Es ist konstant und hängt nicht von der Schleife ab.
Jv42

1
Getestet durch Generieren von 1M Passwörtern mit jeweils 10 Zeichen und es funktioniert großartig.
NaXir

1
NSArrayCaches sein length, sollte kein Leistungsengpass sein.
Pascal

Genau. Es ist ein einfacher Zugang zu Immobilien. Es zählt sich nicht jedes Mal, wenn Sie fragen.
Devios1

45

Sicherlich können Sie dies kürzer machen:

+(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
warum die -1? Daran ist überhaupt nichts auszusetzen. Es ist wie das kleinste, das unter allen Antworten am optimiertesten ist.
John Riselvato

5
Daran ist nichts auszusetzen. Es ist eine schöne und prägnante Lösung. (Ich wünschte, SO würde einen Kommentar zu Abstimmungen erzwingen.)
alvi

Beste Lösung. Der einzige Kommentar, ich würde es statische Methode machen.
Andrei Tchijov

9
Der einzige Nachteil ist, dass es nicht wirklich alphanumerisch ist, sondern nur Kleinbuchstaben. ;-)
PrimaryFeather

Ich denke, Sie müssen die 25 auf 26 ändern, sonst bekommen Sie nie 'z'.
Marcus Adams

28

Wenn Sie sich nur auf Hex-Zeichen beschränken möchten, können Sie am einfachsten eine UUID generieren:

NSString *uuid = [NSUUID UUID].UUIDString;

Beispielausgabe : 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.

Wenn Sie eine kleinere zufällige Zeichenfolge möchten, können Sie nur die ersten 8 Zeichen erfassen.

Es ist eine Version 4 UUID , die das erste Zeichen in der 3. und 4. Gruppe bedeutet , ist nicht zufällig (sie wird es immer sein 4und einer von 8, 9, AoderB ).

Jedes andere Zeichen in der Zeichenfolge ist völlig zufällig und Sie können über Hunderte von Jahren jede Sekunde Millionen von UUIDs generieren, ohne dass das Risiko groß ist, dass dieselbe UUID zweimal generiert wird.


1
Sie können einfach verwendenNSString *uuid = [UUID UUID]
Orkoden

@orkoden danke, mein Code war von einem iOS 5 Code. Ich werde meine Antwort aktualisieren, um die neuere iOS 6 / OS X 10.8-API zu verwenden.
Abhi Beckert

@AbhiBeckert ist es sicher, nur die ersten 8 Zeichen zu verwenden, ohne das Risiko, die ersten 8 Zeichen zu erhalten?
Vishal Singh

1
@ VishalSingh Ja, es ist sicher, obwohl das Kollisionsrisiko umso höher ist, je kürzer Sie es machen.
Abhi Beckert

3
NSString * uuid = [UUID UUID] .UUIDString; gibt den Fehler "Verwendung der nicht deklarierten Bezeichner-UUID" aus, sodass nur eine kleine Änderung des Codes NSString * uuid = [NSUUID UUID] .UUIDString;
Abbas Mulani

24

Eine Kategorie-Version von Jeff Bs Antwort.

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
Dies ist ein großartiges Beispiel für die Verwendung von Kategorien!
ElmerCat

7

Sie können auch einfach eine UUID generieren. Obwohl sie nicht wirklich zufällig sind, sind sie komplex und einzigartig, was sie für die meisten Verwendungen zufällig erscheinen lässt. Generieren Sie eine Zeichenfolge und nehmen Sie dann einen Zeichenbereich, der der übergebenen Länge entspricht.


Ich würde dringend davon abraten, wenn es um Sicherheit geht. Pseudozufälligkeit ist eine der größten Gefahren, die Hacker bei der Durchdringung von Systemen verwenden, da sie Vorhersagbarkeit bieten. Verwenden Sie so nah wie möglich an der Zufallszahl.
Shayne

5

Schnell

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
Kurz und bündig. Hat für mich funktioniert, außer als ich das Alphabet geändert habe. Es ist abgestürzt, weil die Alphabetlänge fest codiert ist. Ich habe die 64 durch UInt32 (Anzahl (Alphabet)) ersetzt
scootermg

OK. Ich habe den fest codierten 64durch einen berechneten ersetzt upperBound. Ich rechne upperBoundaußerhalb des Blocks, weil ich denke, dass das besser funktioniert.
ma11hew28

'Count' kann nicht mit einer Argumentliste vom Typ '(String)' aufgerufen werden, indem 'alphabet.characters.count' verwendet wird
Zaporozhchenko Oleksandr

return alphabet [alphabet.startIndex.advancedBy (Int (arc4random_uniform (obere Grenze)))
Zaporozhchenko Oleksandr

4

Hier ist ein anderer Weg, um es anzugehen. Anstatt eine vorbereitete Zeichenfolge zu verwenden, können Sie zwischen Ganzzahlen und Zeichen wechseln und eine dynamische Liste der zur Auswahl stehenden Zeichen erstellen. Es ist ziemlich schlank und schnell, hat aber etwas mehr Code.

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

Wenn ich zufällige Zeichen generiere, arbeite ich lieber direkt mit ganzen Zahlen und übersetze sie, anstatt die Liste der Zeichen aufzuschreiben, aus denen ich zeichnen möchte. Wenn Sie die Variablen oben deklarieren, wird das System systemunabhängiger. Bei diesem Code wird jedoch davon ausgegangen, dass Zahlen einen niedrigeren Wert als Buchstaben und Großbuchstaben einen niedrigeren Wert als Kleinbuchstaben haben.


3

Alternative Lösung in 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

Neben der guten Antwort von Melvin habe ich folgende Funktion ( in SWIFT! ) Erstellt , um eine zufällige Zeichenfolge zu erhalten:

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
}

Hier ist ein Testergebnis aus dem Aufruf randomStringOfLength(10): uXa0igA8wm


2

Erzeugt eine alphanumerische Zufallszeichenfolge in Kleinbuchstaben mit der angegebenen Länge:

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

Modifikation einiger Ideen hier und fertig 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))]
        })
    }
}

Verwendung:

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

1

Wenn Sie eine zufällige Unicode-Zeichenfolge möchten, können Sie zufällige Bytes erstellen und dann die gültigen verwenden.

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

Die Konvertierung von NSString nach NSData und zurück ist erforderlich, um eine gültige UTF-8-Zeichenfolge zu erhalten. Beachten Sie, dass die Länge nicht unbedingt der Länge des am Ende erstellten NSString entspricht.


1

Ich habe dies mit einem einfachen char[]anstelle eines NSString *für das Alphabet gemacht. Ich habe dies einer NSString-Kategorie hinzugefügt.

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

Methode zum Aufrufen:


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

Methode:


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

Ergebnisse:


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

1

für 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

Änderung für die Antwort von 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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.