Cocoa'da rastgele bir alfasayısal dize oluşturun


145

Bir yöntemi çağırmak, uzunluğunu iletmek ve rastgele bir alfanümerik dizge oluşturmasını istiyorum.

Dışarıda bu tür işlevlere sahip olabilecek herhangi bir yardımcı kitaplık var mı?

Yanıtlar:


312

İşte hızlı ve kirli bir uygulama. Test edilmedi.

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 yalnızca randomString döndürmelidir. Tamamen yeni bir dizge ayırmak ve başlatmak (ve otomatik olarak yayımlamak değil!) İçin hiçbir neden yoktur.
kevingessner

5
Bunu oraya koyacağım. Basit bir dizinin iyi çalıştığı zamanlar NSStringiçin an kullanmanın bir nedeni yoktur . Aslında, kullanmak bana göre daha az özlü görünüyor . Foundation sınıfları gerçekten faydalıdır, ancak en basit şeyler için kodumuzu geliştirmek yerine gizlemeye hizmet edebilirler. letterschar[letters characterAtIndex:(rand() % [letters length])]letters[rand() % strlen(letters)]
Jonathan Sterling

3
%Cyerine isteyebilirsiniz %c, çünkü characterAtIndex:birunichar
user102008

8
Arc4random kullanmak, dizi uzunluğu ikinin üssü olmadığında taraflı bir sonuç oluşturur. arc4random_uniform bunu düzeltir.
jlukanta

9
derleyici hassasiyeti kaybetmek için bir uyarı verirdi, bu yüzden int'e arc4random_uniform((int)[letters length])
çevirmek

105

Tam olarak istediğin şey değil, ama yine de faydalı:

[[NSProcessInfo processInfo] globallyUniqueString]

Örnek çıktı:

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

2
Bu, soruyu ele almanın en kısa ve en doğrudan yoludur.
adib

İçinde kısa çizgiler olsa bile - bu bir endişe değilse, o zaman harika!
fatuhoku

Bir mil ile en iyi cevap
Rambatino

"Kakaoda rastgele bir alfasayısal dizi oluşturma" ihtiyacım için mükemmel. Tam olarak OP'nin sorduğu şey değil, çünkü YAGNI'nin "uzunluğunu geçme" şartını eklediğinden!
jkoreska

5
Bu muhtemelen çoğu kullanım için uygundur, ancak güvenlik amacıyla rastgele bir dizeye ihtiyacınız varsa KULLANMAYIN. Benzersiz! = Rastgele. Uzunluk sabittir, kullanılan karakter aralığı sınırlıdır (0-9, AF, - = 17, aZ. 0-9 için 62'ye karşılık). Bu dize benzersizdir ancak tahmin edilebilir.
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
Gerçekten alphabether seferin uzunluğunu sorgulamanız gerekiyor mu? Sabittir ve döngüye bağlı değildir.
jv42

1
Her biri 10 karakterlik 1 milyon şifre oluşturarak test edildi ve harika çalışıyor.
NaXir

1
NSArrayönbelleğe alır, lengthperformans darboğazı olmamalıdır.
Pascal

Katılıyorum. Bu basit bir mülk erişimi. Her sorduğunuzda kendini saymıyor.
devios1

45

Elbette bunu kısaltabilirsiniz:

+(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
neden -1? Bunda yanlış bir şey yok. Tüm yanıtlar arasında en optimize edilmiş en küçüğü gibi.
John Riselvato

5
Bunda yanlış bir şey yok. Güzel ve özlü bir çözüm. (Keşke SO'nun olumsuz oylara bir yorum getirmesini isterdim.)
alvi

En iyi çözüm. Tek yorum, bunu statik yöntem yapardım.
Andrei Tchijov

9
Tek dezavantajı, gerçekten alfanümerik olmaması, sadece küçük harfler olmasıdır. ;-)
PrimaryFeather

Sanırım 25'i 26 olarak değiştirmeniz gerekiyor, aksi takdirde asla "z" alamazsınız.
Marcus Adams

28

Kendinizi yalnızca onaltılık karakterlerle sınırlamak istiyorsanız, en basit seçenek bir UUID oluşturmaktır:

NSString *uuid = [NSUUID UUID].UUIDString;

Örnek çıkışı: 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.

Daha küçük bir rastgele dizge istiyorsanız, yalnızca ilk 8 karakteri yakalayabilirsiniz.

O (her zaman olacak 3. ve 4. gruptaki ilk karakteri anlamına rastgele olmayan bir sürüm 4 UUID var 4ve biri 8, 9, Aveya B).

Dizedeki diğer her karakter tamamen rastgeledir ve aynı UUID'nin iki kez üretilme riski olmadan yüzlerce yıl boyunca her saniye milyonlarca UUID üretebilirsiniz.


1
Basitçe kullanabilirsinizNSString *uuid = [UUID UUID]
orkoden

@orkoden teşekkürler, kodum bazı iOS 5 kodlarından geliyordu. Cevabımı daha yeni iOS 6 / OS X 10.8 API'yi kullanmak için güncelleyeceğim.
Abhi Beckert

@AbhiBeckert aynı ilk 8 karakteri alma riski olmadan sadece ilk 8 karakteri kullanmak güvenli midir?
Vishal Singh

1
@VishalSingh evet, güvenlidir, ancak açıkçası ne kadar kısa olursa çarpışma riskiniz o kadar yüksek olur.
Abhi Beckert

3
NSString * uuid = [UUID UUID] .UUIDString; "Bildirilmemiş tanımlayıcı UUID kullanımı" hatası verir, bu nedenle koddaki küçük bir değişiklik NSString * uuid = [NSUUID UUID] .UUIDString;
Abbas Mulani

24

Jeff B'nin cevabının bir kategori versiyonu.

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
Bu, Kategorilerin nasıl kullanılacağına dair harika bir örnek!
ElmerCat

7

Ayrıca bir UUID de oluşturabilirsiniz. Gerçekten rastgele olmasalar da, karmaşık ve benzersizdirler, bu da çoğu kullanım için rastgele görünmelerine neden olur. Dize olarak bir tane oluşturun ve ardından geçirilen uzunluğa eşit bir karakter aralığı alın.


Güvenlikle ilgili herhangi bir şey için buna şiddetle karşı çıkarım. Sözde rastgelelik, öngörülebilirlik sağladıkları için bilgisayar korsanlarının penetrasyon sistemlerinde kullandıkları en büyük güvenlik açıklarından biridir. Mümkün olduğunca gerçek rastgele yakın kullanın.
Shayne 13

5

Swift

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
Kısa ve tatlı. Alfabeyi değiştirdiğim zamanlar dışında benim için çalıştı, alfabe uzunluğu sabit kodlandığı için çöktü. 64'ü UInt32 (sayı (alfabe)) ile değiştirdim
scootermg

TAMAM. Sabit kodlu 64bir bilgisayarla değiştirdim upperBound. upperBoundBlok dışında hesaplama yapıyorum çünkü bunun daha iyi performans gösterdiğini düşünüyorum.
ma11hew28

'(Dize)' türü bağımsız değişken listesiyle 'alfabe.characters.count' kullanılarak 'sayım'
Zaporozhchenko Oleksandr

1
dönüş alfabesi [alphabet.startIndex.advancedBy (Int (arc4random_uniform (UpperBound)))
Zaporozhchenko Oleksandr

4

İşte bunun üstesinden gelmenin farklı bir yolu. Hazır bir karakter dizisi kullanmak yerine, tamsayılar ve karakterler arasında dönüşüm yapabilir ve seçilecek dinamik bir karakter listesi oluşturabilirsiniz. Oldukça yalın ve hızlıdır, ancak biraz daha fazla kodu vardır.

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

Rastgele karakter oluşturma yaparken, çizmek istediğim karakterlerin listesini yazmak yerine, doğrudan tamsayılarla çalışmayı ve onları atmayı tercih ederim. Değişkenleri üstte bildirmek onu daha sistemden bağımsız kılar, ancak bu kod sayıların harflerden daha düşük bir değere sahip olacağını ve büyük harflerin küçük harflerden daha düşük bir değere sahip olacağını varsayar.


3

Swift'de alternatif çözüm

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

Melvin tarafından verilen iyi yanıta ek olarak, rastgele bir dize elde etmek için yaptığım ( SWIFT'de! ) Bir işlev :

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
}

UXa0igA8wm çağrısından elde edilen bir test sonucu randomStringOfLength(10):


2

Verilen uzunlukta küçük harfli alfanümerik rastgele dize oluşturur:

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

Birkaç fikrin burada ve Swift 4.0'da değiştirilmesi

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

Kullanım:

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

1

Rastgele bir unicode dizesi istiyorsanız, rastgele baytlar oluşturabilir ve ardından geçerli olanları kullanabilirsiniz.

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

NSString'den NSData'ya ve geriye dönüşüm, geçerli bir UTF-8 dizesi elde etmek için gereklidir. Uzunluğun, sonunda oluşturulan NSString'in uzunluğu olması gerekmediğini unutmayın.


1

Bunu alfabe için char[]bir yerine basit kullanarak yaptım NSString *. Bunu bir NSString kategorisine ekledim.

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

Arama yöntemi:


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

Yöntem:


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

Sonuçlar:


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

1

Swift 3.0 için

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

Keithyip'in cevabı için değişiklik:

+ (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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.