Hasilkan string alfanumerik acak dalam Kakao

145

Saya ingin memanggil metode, berikan panjangnya dan buatkan string alfanumerik acak.

Apakah ada perpustakaan utilitas di luar sana yang mungkin memiliki banyak jenis fungsi ini?

Menangkal
sumber

Jawaban:

312

Berikut ini adalah implementasi cepat dan kotor. Belum diuji.

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
sumber
1
genRandStringLength seharusnya mengembalikan randomString. Tidak ada alasan untuk mengalokasikan dan init (dan bukan autorelease!) String yang sama sekali baru.
kevingessner
5
Hanya akan meletakkan ini di luar sana. Tidak ada alasan untuk menggunakan NSStringuntuk letterssaat sederhana chararray yang akan bekerja dengan baik. Bahkan, menggunakan [letters characterAtIndex:(rand() % [letters length])]bagi saya tampaknya kurang ringkas daripada adil letters[rand() % strlen(letters)]. Kelas-kelas Foundation sangat membantu, tetapi untuk hal-hal yang paling sederhana, mereka dapat berfungsi untuk mengaburkan kode kita daripada meningkatkannya.
Jonathan Sterling
3
Anda mungkin ingin, %Cbukan %c, karena characterAtIndex:mengembalikanunichar
user102008
8
Menggunakan arc4random akan menghasilkan hasil yang bias ketika panjang array bukan kekuatan dua. arc4random_uniform memperbaikinya.
jlukanta
9
oh kompiler akan memberikan peringatan untuk kehilangan presisi, jadi lebih baik untuk melemparkan ke intarc4random_uniform((int)[letters length])
knshn
103

Tidak persis apa yang Anda tanyakan, tetapi masih berguna:

[[NSProcessInfo processInfo] globallyUniqueString]

Output sampel:

450FEA63-2286-4B49-8ACC-9822C7D4356B-1376-00000239A4AC4FD5
myeyesareblind
sumber
2
Sejauh ini, ini adalah cara terpendek dan paling mudah untuk menjawab pertanyaan tersebut.
adib
Bahkan jika itu memiliki tanda hubung di dalamnya - jika itu bukan masalah maka hebat!
fatuhoku
Jawaban terbaik sejauh satu mil
Rambatino
Sempurna untuk kebutuhan saya untuk "menghasilkan string alfanumerik acak dalam kakao". Tidak persis apa yang diminta OP hanya karena dia menambahkan persyaratan untuk "berikan saja" yang YAGNI!
jkoreska
5
Ini mungkin ok untuk sebagian besar penggunaan tetapi JANGAN GUNAKAN jika Anda memerlukan string acak untuk tujuan keamanan. Unik! = Acak. Panjangnya konstan, kisaran karakter yang digunakan terbatas (0-9, AF, - = 17, vs 62 untuk aZ. 0-9). String ini unik tetapi dapat diprediksi.
amcc 2-15
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
sumber
13
Apakah Anda benar-benar perlu menanyakan panjang alphabetsetiap waktu? Itu konstan dan tidak tergantung pada loop.
jv42
1
Diuji dengan menghasilkan 1M kata sandi masing-masing 10 karakter dan itu berfungsi dengan baik.
NaXir
1
NSArraycache-nya length, seharusnya tidak menjadi hambatan kinerja.
Pascal
Saya setuju. Ini akses properti sederhana. Itu tidak menghitung sendiri setiap kali Anda bertanya.
devios1
45

Tentunya Anda dapat membuat ini lebih pendek:

+(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
sumber
2
mengapa -1? Tidak ada yang salah dengan ini sama sekali. Ini seperti jawaban terkecil yang paling optimal dari semua jawaban.
John Riselvato
5
Tidak ada yang salah dengan yang satu ini. Ini solusi yang bagus dan ringkas. (Saya berharap SO akan menegakkan komentar pada downvotes.)
alvi
Solusi terbaik. Satu-satunya komentar, saya akan menjadikannya metode statis.
Andrei Tchijov
9
Satu-satunya downside adalah bahwa itu tidak benar-benar alfanumerik, tetapi hanya huruf kecil. ;-)
PrimaryFeather
Saya pikir Anda perlu mengubah 25 menjadi 26, jika tidak, Anda tidak akan pernah mendapatkan 'z'.
Marcus Adams
28

Jika Anda ingin membatasi diri hanya untuk karakter hex, maka opsi paling sederhana adalah membuat UUID:

NSString *uuid = [NSUUID UUID].UUIDString;

Contoh output: 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.

Jika Anda ingin string acak yang lebih kecil maka Anda bisa mengambil 8 karakter pertama saja.

Ini adalah versi 4 UUID yang berarti karakter pertama dalam 3 dan 4 kelompok tidak acak (mereka akan selalu 4dan salah 8, 9, Aatau B).

Setiap karakter lain dalam string sepenuhnya acak dan Anda dapat menghasilkan jutaan UUID setiap detik selama ratusan tahun tanpa banyak risiko UUID yang sama dihasilkan dua kali.

Abhi Beckert
sumber
1
Anda cukup menggunakanNSString *uuid = [UUID UUID]
orkoden
@orkoden terima kasih, kode saya berasal dari beberapa kode iOS 5. Saya akan memperbarui jawaban saya untuk menggunakan iOS 6 / OS X 10.8 API yang lebih baru.
Abhi Beckert
@AbhiBeckert, apakah aman menggunakan hanya 8 karakter pertama tanpa risiko mendapatkan 8 karakter pertama yang sama?
Vishal Singh
1
@VishalSingh ya, itu aman, meskipun jelas semakin pendek Anda membuatnya semakin tinggi risiko tabrakan.
Abhi Beckert
3
NSString * uuid = [UUID UUID] .UUIDString; akan memberi Anda kesalahan "Penggunaan UUID yang tidak dideklarasikan", jadi hanya perubahan kecil dalam penggunaan kode NSString * uuid = [NSUUID UUID] .UUIDString;
Abbas Mulani
24

Versi kategori dari jawaban 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
keithyip
sumber
1
Ini adalah contoh yang bagus tentang bagaimana menggunakan Kategori!
ElmerCat
7

Anda juga bisa membuat UUID. Meskipun tidak benar-benar acak, mereka rumit dan unik yang membuatnya tampak acak untuk sebagian besar kegunaan. Hasilkan satu sebagai string dan kemudian ambil rentang karakter yang sama dengan panjang yang dilewati.

TechZen
sumber
Saya akan sangat menyarankan hal ini untuk keamanan apa pun yang terkait. Pseudo-randomness adalah salah satu vunerabilities vunerabilities terbesar yang digunakan dalam sistem penetrasi, karena mereka memberikan prediktabilitas. Gunakan sedekat mungkin dengan acak-nyata.
Shayne
5

Cepat

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
sumber
1
Pendek & manis. Bekerja untuk saya kecuali ketika saya mengubah alfabet, itu macet karena panjang alfabet adalah kode keras. Saya mengganti 64 dengan UInt32 (hitungan (alfabet))
scootermg
BAIK. Saya mengganti hardcoded 64dengan yang dihitung upperBound. Saya menghitung di upperBoundluar blok karena saya pikir itu berkinerja lebih baik.
ma11hew28
Tidak dapat memohon 'hitung' dengan daftar argumen tipe '(String)' yang menangani dengan menggunakan 'alphabet.characters.count'
Zaporozhchenko Oleksandr
return alphabet [alphabet.startIndex.advancedBy (Int (arc4random_uniform (upperBound)))
Zaporozhchenko Oleksandr
4

Berikut cara berbeda untuk mengatasinya. Alih-alih menggunakan serangkaian karakter yang sudah disiapkan, Anda dapat memilih antara bilangan bulat dan karakter, dan menghasilkan daftar karakter dinamis untuk dipilih. Ini sangat ramping dan cepat, tetapi memiliki kode sedikit lebih banyak.

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

Ketika saya melakukan pembuatan karakter acak, saya lebih suka bekerja secara langsung dengan bilangan bulat dan melemparkannya, daripada menulis daftar karakter yang ingin saya gunakan. Mendeklarasikan variabel di bagian atas membuatnya lebih sistem independen, tetapi kode ini mengasumsikan bahwa angka akan memiliki nilai lebih rendah dari huruf, dan bahwa huruf besar akan memiliki nilai lebih rendah daripada huruf kecil.

rjferguson
sumber
3

Solusi alternatif di 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
sumber
2

Menambah jawaban bagus yang diberikan oleh Melvin, berikut adalah fungsi yang saya buat ( dalam SWIFT! ) Untuk mendapatkan string acak:

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
}

Berikut ini adalah hasil tes dari panggilan randomStringOfLength(10): uXa0igA8wm

Stan Tatarnykov
sumber
2

Menghasilkan string acak alfanumerik huruf kecil dengan panjang yang diberikan:

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

Modifikasi beberapa ide di sini, dan dalam dilakukan 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))]
        })
    }
}

Pemakaian:

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

Jika Anda menginginkan string unicode acak, Anda bisa membuat byte acak dan kemudian menggunakan yang valid.

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

Konversi dari NSString ke NSData dan kembali diperlukan untuk mendapatkan string UTF-8 yang valid. Sadarilah bahwa panjang tidak harus menjadi panjang NSString yang dibuat pada akhirnya.

orkoden
sumber
1

Saya melakukan ini menggunakan sederhana, char[]bukan NSString *untuk alfabet. Saya menambahkan ini ke kategori 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;
}
Tuan T
sumber
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
sumber
1

Metode menelepon:


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

Metode:


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

Hasil:


## randomString: file_Msci.pdf ##
## randomString: file_xshG.pdf ##
## randomString: file_abAD.pdf ##
## randomString: file_HVwV.pdf ##
emotalitas
sumber
1

untuk 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
}
WARRIOR SAHAM
sumber
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;
}
Terima kasih
sumber
0

Modifikasi untuk jawaban 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
sumber