Wygeneruj losowy ciąg alfanumeryczny w kakao


145

Chcę wywołać metodę, podać jej długość i wygenerować losowy ciąg alfanumeryczny.

Czy są jakieś biblioteki narzędziowe, które mogą mieć kilka tego typu funkcji?

Odpowiedzi:


312

Oto szybka i brudna implementacja. Nie był testowany.

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 powinno po prostu zwrócić randomString. Nie ma powodu, aby przydzielać i inicjować (a nie autorelease) cały nowy ciąg.
kevingessner

5
Po prostu zamierzam to opublikować. Nie ma powodu, aby używać NSStringfor, lettersgdy prosta chartablica działałaby dobrze. W rzeczywistości użycie [letters characterAtIndex:(rand() % [letters length])]wydaje mi się mniej zwięzłe niż zwykłe letters[rand() % strlen(letters)]. Klasy Foundation są naprawdę pomocne, ale w najprostszych rzeczach mogą służyć raczej do zaciemniania naszego kodu niż do jego ulepszania.
Jonathan Sterling,

3
możesz chcieć %Czamiast %c, ponieważ characterAtIndex:zwracaunichar
user102008

8
Użycie arc4random wygenerowałoby odchylenie, gdy długość tablicy nie jest potęgą dwóch. arc4random_uniform rozwiązuje ten problem.
jlukanta

9
oh kompilator dałby ostrzeżenie o utracie precyzji, więc lepiej rzutować na intarc4random_uniform((int)[letters length])
knshn

103

Nie do końca o to pytasz, ale nadal przydatne:

[[NSProcessInfo processInfo] globallyUniqueString]

Przykładowe dane wyjściowe:

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

2
To zdecydowanie najkrótszy i najprostszy sposób odpowiedzi na to pytanie.
adib

Nawet jeśli ma w sobie myślniki - jeśli to nie dotyczy, to super!
fatuhoku

Najlepsza odpowiedź o milę
Rambatino

Idealne na moją potrzebę „wygenerowania losowego ciągu alfanumerycznego w kakao”. Nie dokładnie to, o co pyta OP, tylko dlatego, że dodaje wymóg „przekazania mu długości”, o co YAGNI!
jkoreska

5
Jest to prawdopodobnie w porządku dla większości zastosowań, ale NIE UŻYWAJ, jeśli potrzebujesz losowego ciągu znaków ze względów bezpieczeństwa. Unikalne! = Losowe. Długość jest stała, zakres użytych znaków jest ograniczony (0-9, AF, - = 17, vs 62 dla aZ. 0-9). Ten ciąg jest wyjątkowy, ale przewidywalny.
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
Czy naprawdę musisz sprawdzać długość alphabetkażdego czasu? Jest stała i nie zależy od pętli.
jv42

1
Testowane przez wygenerowanie 1 mln haseł po 10 znaków każde i działa świetnie.
NaXir

1
NSArraybuforuje swoje length, nie powinno być wąskim gardłem wydajności.
Pascal

Zgadzam się. To prosty dostęp do nieruchomości. Nie liczy się za każdym razem, gdy pytasz.
devios1

45

Z pewnością możesz to skrócić:

+(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
dlaczego -1? Nie ma w tym nic złego. To jak najmniejsza, najbardziej zoptymalizowana ze wszystkich odpowiedzi.
John Riselvato,

5
W tym nie ma nic złego. To ładne i zwięzłe rozwiązanie. (Chciałbym, żeby SO wymusiło komentarz na temat głosów przeciw.)
alvi

Najlepsze rozwiązanie. Jedyny komentarz, uczyniłbym to metodą statyczną.
Andrei Tchijov

9
Jedynym minusem jest to, że tak naprawdę nie jest to alfanumeryczne, ale tylko małe litery. ;-)
PrimaryFeather

Myślę, że musisz zmienić 25 na 26, w przeciwnym razie nigdy nie otrzymasz „z”.
Marcus Adams

28

Jeśli chcesz ograniczyć się tylko do znaków szesnastkowych, najprostszą opcją jest wygenerowanie UUID:

NSString *uuid = [NSUUID UUID].UUIDString;

Przykład Wydajność: 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.

Jeśli chcesz mieć mniejszy losowy ciąg, możesz pobrać tylko pierwsze 8 znaków.

Jest to wersja 4 UUID co oznacza pierwszy znak w grupie 3 i 4 nie jest przypadkowa (zawsze będą 4i jeden 8, 9, Alub B).

Każdy inny znak w ciągu jest w pełni losowy i możesz generować miliony identyfikatorów UUID co sekundę przez setki lat bez większego ryzyka, że ​​ten sam UUID zostanie wygenerowany dwukrotnie.


1
Możesz po prostu użyćNSString *uuid = [UUID UUID]
orkoden,

@orkoden dzięki, mój kod pochodzi z jakiegoś kodu iOS 5. Zaktualizuję swoją odpowiedź, aby korzystać z nowszego interfejsu API iOS 6 / OS X 10.8.
Abhi Beckert

@AbhiBeckert czy bezpiecznie jest używać tylko pierwszych 8 znaków bez ryzyka uzyskania tych samych pierwszych 8 znaków?
Vishal Singh

1
@VishalSingh tak, jest to bezpieczne, chociaż oczywiście im krótszy czas, tym większe ryzyko kolizji.
Abhi Beckert

3
NSString * uuid = [UUID UUID] .UUIDString; spowoduje wyświetlenie błędu „Użycie niezadeklarowanego identyfikatora UUID”, więc wystarczy niewielka zmiana w kodzie, używając NSString * uuid = [NSUUID UUID] .UUIDString;
Abbas Mulani

24

Kategoriaowa wersja odpowiedzi Jeffa 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
To świetny przykład korzystania z kategorii!
ElmerCat

7

Możesz też po prostu wygenerować UUID. Chociaż nie są naprawdę losowe, są złożone i niepowtarzalne, co sprawia, że ​​w większości zastosowań wydają się losowe. Wygeneruj jeden jako ciąg, a następnie weź zakres znaków równy przekazanej długości.


Zdecydowanie odradzam to ze względu na wszystko związane z bezpieczeństwem. Pseudolosowość jest jednym z największych ataków vunerability wykorzystywanych przez hakerów w penetrowaniu systemów, ponieważ zapewnia przewidywalność. Używaj tak blisko rzeczywistego losowego, jak to możliwe.
Shayne

5

Szybki

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
Krótkie i słodkie. Pracował dla mnie, z wyjątkiem sytuacji, gdy zmieniłem alfabet, zawiesił się, ponieważ długość alfabetu jest zakodowana na stałe. Wymieniłem 64 na UInt32 (count (alfabet))
scootermg

DOBRZE. Zamieniłem zakodowane na stałe 64na obliczone upperBound. Obliczam upperBoundpoza blokiem, ponieważ myślę, że to działa lepiej.
ma11hew28

Nie można wywołać `` count '' z listą argumentów typu `` (String) '' za pomocą
Zaporożczenko Oleksandr

return alphabet [alphabet.startIndex.advancedBy (Int (arc4random_uniform (upperBound)))
Zaporożczenko Oleksandr

4

Oto inny sposób rozwiązania tego problemu. Zamiast używać przygotowanego ciągu znaków, możesz rzutować między liczbami całkowitymi i znakami oraz wygenerować dynamiczną listę znaków do wyboru. Jest dość oszczędny i szybki, ale ma nieco więcej kodu.

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

Kiedy tworzę losowe generowanie znaków, wolę pracować bezpośrednio z liczbami całkowitymi i rzucać je na drugą stronę, zamiast pisać listę znaków, z których chcę narysować. Zadeklarowanie zmiennych u góry czyni je bardziej niezależnymi od systemu, ale ten kod zakłada, że ​​liczby będą miały mniejszą wartość niż litery, a wielkie litery będą miały mniejszą wartość niż małe litery.


3

Alternatywne rozwiązanie w 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

Dodając do dobrej odpowiedzi udzielonej przez Melvina, oto funkcja, którą wykonałem ( w SWIFT! ), Aby uzyskać losowy ciąg:

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
}

Oto wynik testu wywołania randomStringOfLength(10): uXa0igA8wm


2

Generuje mały alfanumeryczny ciąg losowy o podanej długości:

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

Modyfikacja kilku pomysłów tutaj oraz w gotowym 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))]
        })
    }
}

Stosowanie:

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

1

Jeśli chcesz mieć losowy ciąg znaków Unicode, możesz utworzyć losowe bajty, a następnie użyć prawidłowych.

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

Konwersja z NSString na NSData iz powrotem jest konieczna, aby uzyskać prawidłowy ciąg znaków UTF-8. Należy pamiętać, że długość niekoniecznie będzie długością utworzonego na końcu ciągu NSS.


1

Zrobiłem to za pomocą prostego alfabetu char[]zamiast NSString *litery. Dodałem to do kategorii 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

Sposób połączenia:


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

Metoda:


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

Wyniki:


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

1

dla 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

Modyfikacja odpowiedzi 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;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.