Hasilkan string alfanumerik acak di Swift


208

Bagaimana saya bisa menghasilkan string alfanumerik acak di Swift?

Jawaban:


355

Swift 4.2 Update

Swift 4.2 memperkenalkan peningkatan besar dalam berurusan dengan nilai dan elemen acak. Anda dapat membaca lebih lanjut tentang peningkatan tersebut di sini . Berikut ini metode yang direduksi menjadi beberapa baris:

func randomString(length: Int) -> String {
  let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  return String((0..<length).map{ _ in letters.randomElement()! })
}

Pembaruan 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
}

Jawaban asli:

func randomStringWithLength (len : Int) -> NSString {

    let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

    var randomString : NSMutableString = NSMutableString(capacity: len)

    for (var i=0; i < len; i++){
        var length = UInt32 (letters.length)
        var rand = arc4random_uniform(length)
        randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
    }

    return randomString
}

1
Apakah ada cara saya dapat memodifikasi di atas untuk memastikan bahwa string alfanumerik yang dihasilkan hanya sepanjang 6 atau 8 karakter?
ksa_coder

4
randomString (panjang: 6) atau randomString (panjang: 8)
Simon H

58

Inilah solusi yang siap digunakan dalam sintaks Swiftier . Anda cukup menyalin dan menempelkannya:

func randomAlphaNumericString(length: Int) -> String {
    let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let allowedCharsCount = UInt32(allowedChars.characters.count)
    var randomString = ""

    for _ in 0..<length {
        let randomNum = Int(arc4random_uniform(allowedCharsCount))
        let randomIndex = allowedChars.index(allowedChars.startIndex, offsetBy: randomNum)
        let newCharacter = allowedChars[randomIndex]
        randomString += String(newCharacter)
    }

    return randomString
}

Jika Anda lebih suka Kerangka yang juga memiliki beberapa fitur yang lebih berguna maka jangan ragu untuk checkout proyek saya HandySwift . Ini juga termasuk solusi yang bagus untuk string alfanumerik acak :

String(randomWithLength: 8, allowedCharactersType: .alphaNumeric) // => "2TgM5sUG"

49

Anda dapat menggunakannya juga dengan cara berikut:

extension String {

    static func random(length: Int = 20) -> String {

        let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        var randomString: String = ""

        for _ in 0..<length {

            let randomValue = arc4random_uniform(UInt32(base.characters.count))
            randomString += "\(base[base.startIndex.advancedBy(Int(randomValue))])"
        }

        return randomString
    }
}

Penggunaan sederhana:

let randomString = String.random()

Sintaks Swift 3:

extension String {

    static func random(length: Int = 20) -> String {
        let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        var randomString: String = ""

        for _ in 0..<length {
            let randomValue = arc4random_uniform(UInt32(base.characters.count))
            randomString += "\(base[base.index(base.startIndex, offsetBy: Int(randomValue))])"
        }
        return randomString
    }
}

Sintaks Swift 4:

extension String {

    static func random(length: Int = 20) -> String {
        let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        var randomString: String = ""

        for _ in 0..<length {
            let randomValue = arc4random_uniform(UInt32(base.count))
            randomString += "\(base[base.index(base.startIndex, offsetBy: Int(randomValue))])"
        }
        return randomString
    }
}


11

Dengan Swift 4.2, taruhan terbaik Anda adalah membuat string dengan karakter yang Anda inginkan dan kemudian menggunakan randomElement untuk memilih setiap karakter:

let length = 32
let characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomCharacters = (0..<length).map{_ in characters.randomElement()!}
let randomString = String(randomCharacters)

Saya lebih detail tentang perubahan ini di sini .


3
Alih-alih peta Anda dapat menggunakan compactMap dan kemudian tidak perlu! operator. ;)
Kristaps Grinbergs

1
Hey @KristapsGrinbergs! Pikir saya adalah bahwa membuka paksa akan memiliki kinerja yang lebih baik daripada menggunakan compactMap.
leogdion

11

DIPERBARUI 2019.

Dalam kasus yang tidak biasa itu

masalah kinerja.

Berikut adalah fungsi yang sangat jelas yang menyimpan :

func randomNameString(length: Int = 7)->String{
    
    enum s {
        static let c = Array("abcdefghjklmnpqrstuvwxyz12345789")
        static let k = UInt32(c.count)
    }
    
    var result = [Character](repeating: "-", count: length)
    
    for i in 0..<length {
        let r = Int(arc4random_uniform(s.k))
        result[i] = s.c[r]
    }
    
    return String(result)
}

Ini untuk saat Anda memiliki set karakter yang telah diperbaiki .

Tip berguna:

Perhatikan bahwa "abcdefghjklmnpqrstuvwxyz12345789" menghindari karakter 'buruk'

Tidak ada 0, o, O, i, dll ... karakter yang sering membingungkan manusia.

Ini sering dilakukan untuk kode pemesanan dan kode serupa yang akan digunakan pelanggan manusia.


1
Upvoting untuk repeating:count:.
Cœur

10

Sederhana dan Cepat - UUID (). UuidString

// Mengembalikan string yang dibuat dari UUID, seperti "E621E1F8-C36C-495A-93FC-0C247A3E6E5F"

public uarString: String {get}

https://developer.apple.com/documentation/foundation/uuid

Swift 3.0

let randomString = UUID().uuidString //0548CD07-7E2B-412B-AD69-5B2364644433
print(randomString.replacingOccurrences(of: "-", with: ""))
//0548CD077E2B412BAD695B2364644433

EDIT

Tolong jangan bingung dengan UIDevice.current.identifierForVendor?.uuidStringitu tidak akan memberikan nilai acak.


6

Versi Swift 2.2

// based on https://gist.github.com/samuel-mellert/20b3c99dec168255a046
// which is based on https://gist.github.com/szhernovoy/276e69eb90a0de84dd90
// Updated to work on Swift 2.2

func randomString(length: Int) -> String {
    let charactersString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let charactersArray : [Character] = Array(charactersString.characters)

    var string = ""
    for _ in 0..<length {
        string.append(charactersArray[Int(arc4random()) % charactersArray.count])
    }

    return string
}

Pada dasarnya panggil metode ini yang akan menghasilkan string acak panjang bilangan bulat yang diserahkan ke fungsi. Untuk mengubah karakter yang mungkin, cukup edit string karakterString. Mendukung karakter unicode juga.

https://gist.github.com/gingofthesouth/54bea667b28a815b2fe33a4da986e327


2
Untuk beberapa alasan yang disayangkan, versi ini terkadang memberikanEXC_BAD_INSTRUCTION
Joe

Hai Joe, apakah Anda memiliki kode demo yang dapat mereproduksi kesalahan ini?
Ernest Cunningham

Biarkan saya melihat apa yang bisa saya lakukan; Saya hanya menyebutnya apa adanya di outlet tindakan IB dengan let random = randomString(16). EXC hanya di perangkat nyata dan saya tidak melihatnya di simulator dan itu terputus-putus di perangkat.
Joe

1
Lihat pertanyaan SO ini untuk alasan mengapa ini lumpuh separuh waktu pada perangkat 32-bit: stackoverflow.com/questions/25274265/…
julien_c

Penting: random % count tidak tidak (selalu) membuat distribusi seragam. Jika ini relevan bagi Anda, lihat jawaban lain yang digunakan arc4random_uniform().
Raphael

6

Untuk orang-orang yang tidak ingin mengetikkan seluruh rangkaian karakter:

func randomAlphanumericString(length: Int) -> String  {
    enum Statics {
        static let scalars = [UnicodeScalar("a").value...UnicodeScalar("z").value,
                              UnicodeScalar("A").value...UnicodeScalar("Z").value,
                              UnicodeScalar("0").value...UnicodeScalar("9").value].joined()

        static let characters = scalars.map { Character(UnicodeScalar($0)!) }
    }

    let result = (0..<length).map { _ in Statics.characters.randomElement()! }
    return String(result)
}

5

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
}

1
Apakah Anda mencoba kode itu? Apakah Anda memperhatikan bahwa panjang string yang dikembalikan salah, dan hanya ada digit? Lihat stackoverflow.com/q/39566062/1187415 , yang memiliki masalah yang sama.
Martin R

@ MartinR terima kasih telah menunjukkannya. Saya telah memperbarui jawaban saya
S1LENT WARRIOR

5

Acak murni Swift Stringdari mana saja CharacterSet.

Pemakaian: CharacterSet.alphanumerics.randomString(length: 100)

extension CharacterSet {
    /// extracting characters
    /// https://stackoverflow.com/a/52133647/1033581
    public func characters() -> [Character] {
        return codePoints().compactMap { UnicodeScalar($0) }.map { Character($0) }
    }
    public func codePoints() -> [Int] {
        var result: [Int] = []
        var plane = 0
        for (i, w) in bitmapRepresentation.enumerated() {
            let k = i % 8193
            if k == 8192 {
                plane = Int(w) << 13
                continue
            }
            let base = (plane + k) << 3
            for j in 0 ..< 8 where w & 1 << j != 0 {
                result.append(base + j)
            }
        }
        return result
    }

    /// building random string of desired length
    /// https://stackoverflow.com/a/42895178/1033581
    public func randomString(length: Int) -> String {
        let charArray = characters()
        let charArrayCount = UInt32(charArray.count)
        var randomString = ""
        for _ in 0 ..< length {
            randomString += String(charArray[Int(arc4random_uniform(charArrayCount))])
        }
        return randomString
    }
}

The characters()fungsi implementasi saya tercepat dikenal .


3
func randomString(length: Int) -> String {
    // whatever letters you want to possibly appear in the output (unicode handled properly by Swift)
    let letters = "abcABC012你好吗😀🐱💥∆𝚹∌⌘"
    let n = UInt32(letters.characters.count)
    var out = ""
    for _ in 0..<length {
        let index = letters.startIndex.advancedBy(Int(arc4random_uniform(n)))
        out.append(letters[index])
    }
    return out
}

3

Saya bahkan lebih Swift-IER pelaksanaan pertanyaan:

func randomAlphanumericString(length: Int) -> String {

    let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".characters
    let lettersLength = UInt32(letters.count)

    let randomCharacters = (0..<length).map { i -> String in
        let offset = Int(arc4random_uniform(lettersLength))
        let c = letters[letters.startIndex.advancedBy(offset)]
        return String(c)
    }

    return randomCharacters.joinWithSeparator("")
}

3

Loop gratis, meskipun terbatas hingga 43 karakter. Jika Anda membutuhkan lebih banyak, itu dapat dimodifikasi. Pendekatan ini memiliki dua keunggulan dibandingkan hanya menggunakan UUID:

  1. Entropi yang lebih besar dengan menggunakan huruf kecil, karena UUID()hanya menghasilkan huruf besar
  2. A UUIDpaling panjang 36 karakter (termasuk 4 tanda hubung), tetapi hanya 32 karakter yang panjangnya. Jika Anda membutuhkan sesuatu yang lebih lama, atau tidak ingin menyertakan tanda hubung, gunakan base64EncodedStringpegangan ini

Juga, fungsi ini memanfaatkan a UIntuntuk menghindari angka negatif.

 func generateRandom(size: UInt) -> String {
        let prefixSize = Int(min(size, 43))
        let uuidString = UUID().uuidString.replacingOccurrences(of: "-", with: "")
        return String(Data(uuidString.utf8)
            .base64EncodedString()
            .replacingOccurrences(of: "=", with: "")
            .prefix(prefixSize))
    }

Menyebutnya secara berulang untuk memeriksa output:

for _ in 0...10 {
    print(generateRandom(size: 32))
}

Yang menghasilkan:

Nzk3NjgzMTdBQ0FBNDFCNzk2MDRENzZF
MUI5RURDQzE1RTdCNDA3RDg2MTI4QkQx
M0I3MjJBRjVFRTYyNDFCNkI5OUM1RUVC
RDA1RDZGQ0IzQjI1NDdGREI3NDgxM0Mx
NjcyNUQyOThCNzhCNEVFQTk1RTQ3NTIy
MDkwRTQ0RjFENUFGNEFDOTgyQTUxODI0
RDU2OTNBOUJGMDE4NDhEODlCNEQ1NjZG
RjM2MTUxRjM4RkY3NDU2OUFDOTI0Nzkz
QzUwOTE1N0U1RDVENDE4OEE5NTM2Rjcy
Nzk4QkMxNUJEMjYwNDJDQjhBQkY5QkY5
ODhFNjU0MDVEMUI2NEI5QUIyNjNCNkVF

3

Swift 5.0

// Generating Random String
func randomString(length: Int) -> String {
    let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    return String((0..<length).map{ _ in letters.randomElement()! })
}
// Calling to string
label.text = randomString(length: 3)

2

Masalah dengan respons terhadap "Saya perlu string acak" (dalam bahasa apa pun) praktis setiap solusi menggunakan spesifikasi primer cacat panjang string . Pertanyaan-pertanyaan itu sendiri jarang mengungkapkan mengapa string acak diperlukan, tetapi saya akan menantang Anda jarang membutuhkan string acak panjang, katakan 8. Apa yang Anda selalu butuhkan adalah sejumlah string unik , misalnya, untuk digunakan sebagai pengidentifikasi untuk beberapa tujuan.

Ada dua cara utama untuk mendapatkan string unik yang unik : deterministik (yang tidak acak) dan menyimpan / membandingkan (yang memberatkan). Apa yang kita lakukan? Kami menyerah hantu. Kami pergi dengan keunikan probabilistik sebagai gantinya. Artinya, kami menerima bahwa ada beberapa (betapapun kecil) risiko bahwa string kami tidak akan menjadi unik. Di sinilah pemahaman probabilitas tabrakan dan entropi sangat membantu.

Jadi saya akan ulangi kebutuhan yang tidak berubah sebagai membutuhkan sejumlah string dengan risiko pengulangan yang kecil. Sebagai contoh nyata, katakanlah Anda ingin menghasilkan potensi 5 juta ID. Anda tidak ingin menyimpan dan membandingkan setiap string baru, dan Anda ingin mereka menjadi acak, sehingga Anda menerima risiko berulang. Sebagai contoh, katakanlah risiko kurang dari 1 dalam satu triliun peluang berulang. Jadi berapa panjang tali yang Anda butuhkan? Nah, pertanyaan itu tidak ditentukan karena tergantung pada karakter yang digunakan. Tapi yang lebih penting, ini salah arah. Yang Anda butuhkan adalah spesifikasi entropi string, bukan panjangnya. Entropi dapat secara langsung terkait dengan probabilitas pengulangan dalam sejumlah string. Panjang string tidak bisa.

Dan di sinilah perpustakaan seperti EntropyString dapat membantu. Untuk menghasilkan ID acak yang memiliki peluang kurang dari 1 dalam satu triliun untuk diulang dalam 5 juta string menggunakan EntropyString:

import EntropyString

let random = Random()
let bits = Entropy.bits(for: 5.0e6, risk: 1.0e12)
random.string(bits: bits)

"Rrrj6pN4d6GBrFLH4"

EntropyStringmenggunakan set karakter dengan 32 karakter secara default. Ada set karakter yang telah ditentukan sebelumnya, dan Anda dapat menentukan karakter Anda sendiri juga. Misalnya, membuat ID dengan entropi yang sama seperti di atas tetapi menggunakan karakter hex:

import EntropyString

let random = Random(.charSet16)
let bits = Entropy.bits(for: 5.0e6, risk: 1.0e12)
random.string(bits: bits)

"135fe71aec7a80c02dce5"

Perhatikan perbedaan panjang string karena perbedaan jumlah karakter dalam set karakter yang digunakan. Risiko pengulangan dalam jumlah string potensial yang ditentukan adalah sama. Panjang string tidak. Dan yang terbaik dari semuanya, risiko pengulangan dan potensi jumlah string adalah eksplisit. Tidak perlu lagi menebak dengan panjang tali.


2

Jika string acak Anda harus acak-aman, gunakan ini:

import Foundation
import Security

// ...

private static func createAlphaNumericRandomString(length: Int) -> String? {
    // create random numbers from 0 to 63
    // use random numbers as index for accessing characters from the symbols string
    // this limit is chosen because it is close to the number of possible symbols A-Z, a-z, 0-9
    // so the error rate for invalid indices is low
    let randomNumberModulo: UInt8 = 64

    // indices greater than the length of the symbols string are invalid
    // invalid indices are skipped
    let symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

    var alphaNumericRandomString = ""

    let maximumIndex = symbols.count - 1

    while alphaNumericRandomString.count != length {
        let bytesCount = 1
        var randomByte: UInt8 = 0

        guard errSecSuccess == SecRandomCopyBytes(kSecRandomDefault, bytesCount, &randomByte) else {
            return nil
        }

        let randomIndex = randomByte % randomNumberModulo

        // check if index exceeds symbols string length, then skip
        guard randomIndex <= maximumIndex else { continue }

        let symbolIndex = symbols.index(symbols.startIndex, offsetBy: Int(randomIndex))
        alphaNumericRandomString.append(symbols[symbolIndex])
    }

    return alphaNumericRandomString
}

1

Jika Anda hanya memerlukan pengidentifikasi unik, UUID().uuidStringdapat melayani tujuan Anda.


1

Diperbarui untuk Swift 4. Gunakan variabel simpanan yang disimpan pada ekstensi kelas. Ini hanya dihitung sekali.

extension String {

    static var chars: [Character] = {
        return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".map({$0})
    }()

    static func random(length: Int) -> String {
        var partial: [Character] = []

        for _ in 0..<length {
            let rand = Int(arc4random_uniform(UInt32(chars.count)))
            partial.append(chars[rand])
        }

        return String(partial)
    }
}

String.random(length: 10) //STQp9JQxoq

1

SWIFT 4

Menggunakan RandomNumberGenerator untuk kinerja yang lebih baik sebagai rekomendasi Apple

Penggunaan: String.random(20) Hasil:CifkNZ9wy9jBOT0KJtV4

extension String{
   static func random(length:Int)->String{
        let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        var randomString = ""

        while randomString.utf8.count < length{
            let randomLetter = letters.randomElement()
            randomString += randomLetter?.description ?? ""
        }
        return randomString
    }
}

0

Ini adalah solusi Swift -est yang bisa saya buat. Swift 3.0

extension String {
    static func random(length: Int) -> String {
        let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        let randomLength = UInt32(letters.characters.count)

        let randomString: String = (0 ..< length).reduce(String()) { accum, _ in
            let randomOffset = arc4random_uniform(randomLength)
            let randomIndex = letters.index(letters.startIndex, offsetBy: Int(randomOffset))
            return accum.appending(String(letters[randomIndex]))
        }

        return randomString
    } 
}

-1
func randomUIDString(_ wlength: Int) -> String {

    let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    var randomString = ""

    for _ in 0 ..< wlength {
        let length = UInt32 (letters.length)
        let rand = arc4random_uniform(length)
        randomString = randomString.appendingFormat("%C", letters.character(at: Int(rand)));
    }

    return randomString
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.