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?

Station
quelle

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;
}
Jeff B.
quelle
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
myeyesareblind
quelle
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];
}
Melvin
quelle
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;
}
John Riselvato
quelle
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.

Abhi Beckert
quelle
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
keithyip
quelle
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.

TechZen
quelle
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)))]
    })
}
ma11hew28
quelle
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.

rjferguson
quelle
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)
}
Gralex
quelle
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

Stan Tatarnykov
quelle
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;
}
erkanyildiz
quelle
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")
Wex
quelle
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.

Orkoden
quelle
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;
}
Herr T.
quelle
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])]];
}
Peter Lapisu
quelle
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 ##
Emotionalität
quelle
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
}
S1LENT WARRIOR
quelle
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;
}
Der Tank
quelle
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;
}
iutinvg
quelle