Genera una stringa alfanumerica casuale in Cocoa


145

Voglio chiamare un metodo, passarlo per la lunghezza e farlo generare una stringa alfanumerica casuale.

Esistono librerie di utilità là fuori che possono avere un sacco di questi tipi di funzioni?

Risposte:


312

Ecco un'implementazione veloce e sporca. Non è stato testato

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 dovrebbe restituire randomString. Non c'è motivo di allocare e init (e non il rilascio automatico!) Di una stringa completamente nuova.
Kevingessner,

5
Lo metterò qui fuori. Non c'è motivo di usare un NSStringper lettersquando un chararray semplice funzionerebbe bene. In effetti, l'uso [letters characterAtIndex:(rand() % [letters length])]mi sembra meno conciso del semplice letters[rand() % strlen(letters)]. Le classi della Fondazione sono davvero utili, ma per le cose più semplici, possono servire a offuscare il nostro codice piuttosto che migliorarlo.
Jonathan Sterling,

3
potresti preferire %Cinvece %c, perché characterAtIndex:restituisce aunichar
user102008

8
L'uso di arc4random genererebbe un risultato distorto quando la lunghezza dell'array non è una potenza di due. arc4random_uniform risolve questo problema.
jlukanta,

9
oh, il compilatore darebbe un avvertimento per la perdita di precisione, quindi è meglio lanciare intarc4random_uniform((int)[letters length])
knshn

103

Non esattamente quello che chiedi, ma comunque utile:

[[NSProcessInfo processInfo] globallyUniqueString]

Uscita campione:

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

2
Questo è di gran lunga il modo più breve e diretto per rispondere alla domanda.
adib,

Anche se ha trattini - se non è un problema, allora fantastico!
Fatuhoku,

Migliore risposta di un miglio
Rambatino,

Perfetto per il mio bisogno di "generare una stringa alfanumerica casuale in cacao". Non esattamente ciò che OP richiede solo perché aggiunge il requisito di "passare la lunghezza" che YAGNI!
jkoreska,

5
Questo probabilmente va bene per la maggior parte degli usi ma NON UTILIZZARE se è necessaria una stringa casuale per motivi di sicurezza. Unico! = Casuale. La lunghezza è costante, l'intervallo di caratteri utilizzato è limitato (0-9, AF, - = 17, vs 62 per aZ. 0-9). Questa stringa è unica ma prevedibile.
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
Hai davvero bisogno di interrogare la lunghezza di alphabetogni volta? È costante e non dipende dal ciclo.
jv42,

1
Testato generando password 1M di 10 caratteri ciascuna e funziona alla grande.
NaXir,

1
NSArrayla sua cache length, non dovrebbe essere un collo di bottiglia delle prestazioni.
Pascal,

Sono d'accordo. È un semplice accesso alla proprietà. Non si conta da solo ogni volta che lo chiedi.
devios1

45

Sicuramente puoi renderlo più breve:

+(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
perché il -1? Non c'è niente di sbagliato in questo. È come il più piccolo più ottimizzato tra tutte le risposte.
John Riselvato,

5
Niente di sbagliato in questo. È una soluzione piacevole e concisa. (Vorrei che SO imponesse un commento sui
voti negativi

Soluzione migliore. L'unico commento, lo renderei un metodo statico.
Andrei Tchijov,

9
L'unico aspetto negativo è che non è proprio alfanumerico, ma solo lettere minuscole. ;-)
PrimaryFeather

Penso che devi cambiare da 25 a 26, altrimenti non otterrai mai 'z'.
Marcus Adams,

28

Se sei disposto a limitarti ai soli caratteri esadecimali, l'opzione più semplice è generare un UUID:

NSString *uuid = [NSUUID UUID].UUIDString;

Uscita Esempio: 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.

Se vuoi una stringa casuale più piccola, puoi prendere solo i primi 8 caratteri.

E 'un UUID versione 4 il che significa che il primo carattere nel 3 ° e 4 ° gruppo non è casuale (che sarà sempre 4e uno dei 8, 9, Ao B).

Ogni altro carattere nella stringa è completamente casuale e puoi generare milioni di UUID ogni secondo per centinaia di anni senza il rischio che lo stesso UUID venga generato due volte.


1
Puoi semplicemente usareNSString *uuid = [UUID UUID]
orkoden,

@orkoden grazie, il mio codice proveniva da qualche codice iOS 5. Aggiornerò la mia risposta per utilizzare la più recente API iOS 6 / OS X 10.8.
Abhi Beckert,

@AbhiBeckert è sicuro usare solo i primi 8 caratteri senza il rischio di ottenere gli stessi primi 8 caratteri?
Vishal Singh,

1
@VishalSingh sì, è sicuro, anche se ovviamente più corto lo fai, maggiore è il rischio di collisioni.
Abhi Beckert,

3
NSString * uuid = [UUID UUID] .UUIDString; ti darà l'errore "Uso dell'identificatore UUID non dichiarato", quindi solo una piccola modifica nel codice usa NSString * uuid = [NSUUID UUID] .UUIDString;
Abbas Mulani,

24

Una versione di categoria della risposta di 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
Questo è un ottimo esempio di come usare le categorie!
ElmerCat,

7

Potresti anche generare un UUID. Sebbene non siano realmente casuali, sono complessi e unici, il che li rende casuali per la maggior parte degli usi. Generane uno come stringa e quindi accetta un intervallo di caratteri pari alla lunghezza passata.


Sconsiglio caldamente questo per qualsiasi aspetto legato alla sicurezza. La pseudo-casualità è una delle più grandi vunerabilità che gli hacker usano nei sistemi penetranti, perché forniscono prevedibilità. Usa il più vicino possibile al reale.
Shayne,

5

veloce

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
Breve e dolce Ha funzionato per me, tranne quando ho modificato l'alfabeto, si è bloccato perché la lunghezza dell'alfabeto è codificata. Ho sostituito il 64 con UInt32 (conteggio (alfabeto))
scootermg il

OK. Ho sostituito l'hardcoded 64con un calcolato upperBound. Calcolo upperBoundal di fuori del blocco perché penso che funzioni meglio.
ma11hew28,

Impossibile richiamare "count" con un elenco di argomenti di tipo "(String)" handle utilizzando "alphabet.characters.count"
Zaporozhchenko Oleksandr

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

4

Ecco un modo diverso di affrontarlo. Invece di utilizzare una stringa di caratteri preparata, è possibile eseguire il cast tra numeri interi e caratteri e generare un elenco dinamico di caratteri da selezionare. È piuttosto snello e veloce, ma ha un po 'più di codice.

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

Quando eseguo la generazione casuale di caratteri, preferisco lavorare direttamente con numeri interi e gettarli, invece di scrivere l'elenco dei caratteri da cui desidero attingere. Dichiarare le variabili in alto lo rende più indipendente dal sistema, ma questo codice presuppone che i numeri abbiano un valore inferiore rispetto alle lettere e che le lettere maiuscole abbiano un valore inferiore rispetto alle lettere minuscole.


3

Soluzione alternativa 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

Aggiungendo alla buona risposta data da Melvin, ecco una funzione che ho fatto ( in SWIFT! ) Per ottenere una stringa casuale:

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
}

Ecco un risultato del test dalla chiamata randomStringOfLength(10): uXa0igA8wm


2

Genera una stringa casuale alfanumerica minuscola con una determinata lunghezza:

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

Modifica di alcune idee qui e in fatto 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))]
        })
    }
}

Uso:

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

1

Se si desidera una stringa unicode casuale, è possibile creare byte casuali e quindi utilizzare quelli validi.

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

La conversione da NSString a NSData e ritorno è necessaria per ottenere una stringa UTF-8 valida. Tenere presente che la lunghezza non sarà necessariamente la lunghezza della stringa NSS creata alla fine.


1

L'ho fatto usando un semplice char[]invece di un NSString *per l'alfabeto. Ho aggiunto questo a una categoria 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

Metodo per chiamare:


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

Metodo:


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

risultati:


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

1

per 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

Modifica per la risposta di 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.