Generieren Sie in Swift eine zufällige alphanumerische Zeichenfolge


208

Wie kann ich in Swift eine zufällige alphanumerische Zeichenfolge generieren?

Antworten:


354

Swift 4.2 Update

Swift 4.2 führte wesentliche Verbesserungen im Umgang mit zufälligen Werten und Elementen ein. Sie können hier mehr über diese Verbesserungen lesen . Hier ist die Methode auf wenige Zeilen reduziert:

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

Swift 3.0 Update

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
}

Ursprüngliche Antwort:

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
Gibt es eine Möglichkeit, das oben Gesagte zu ändern, um sicherzustellen, dass die generierte alphanumerische Zeichenfolge nur 6 oder 8 Zeichen lang ist?
ksa_coder

4
randomString (Länge: 6) oder randomString (Länge: 8)
Simon H

58

Hier ist eine gebrauchsfertige Lösung in Swiftier-Syntax . Sie können es einfach kopieren und einfügen:

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
}

Wenn Sie ein Framework bevorzugen , das auch einige weitere praktische Funktionen bietet, können Sie mein Projekt HandySwift ausprobieren . Es enthält auch eine schöne Lösung für zufällige alphanumerische Zeichenfolgen :

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

49

Sie können es auch folgendermaßen verwenden:

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

Einfache Verwendung:

let randomString = String.random()

Swift 3-Syntax:

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

Swift 4 Syntax:

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

AKTUALISIERT 2019.

Im ungewöhnlichen Fall das

Leistung ist wichtig.

Hier ist eine extrem klare Funktion, die zwischengespeichert wird :

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

Dies ist der Fall, wenn Sie einen festen, bekannten Zeichensatz haben.

Praktischer Tipp:

Beachten Sie, dass "abcdefghjklmnpqrstuvwxyz12345789" "schlechte" Zeichen vermeidet

Es gibt keine 0, o, O, i usw. Die Charaktere, die Menschen oft verwirren.

Dies geschieht häufig für Buchungscodes und ähnliche Codes, die von menschlichen Kunden verwendet werden.


1
Upvoting für repeating:count:.
Cœur

10

Einfach und schnell - UUID (). UuidString

// Gibt eine aus der UUID erstellte Zeichenfolge zurück, z. B. "E621E1F8-C36C-495A-93FC-0C247A3E6E5F".

public var uuidString: 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

BEARBEITEN

Bitte nicht verwechseln mit , UIDevice.current.identifierForVendor?.uuidStringes wird nicht zufälligen Werten geben.


10

Mit Swift 4.2 erstellen Sie am besten eine Zeichenfolge mit den gewünschten Zeichen und wählen dann mit randomElement jedes Zeichen aus:

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

Ich Detail mehr über diese Änderungen hier .


3
Anstelle von Map können Sie compactMap verwenden, und dann ist dies nicht erforderlich! Operator. ;)
Kristaps Grinbergs

1
Hey @KristapsGrinbergs! Mein Gedanke war, dass erzwungenes Auspacken eine bessere Leistung haben würde als die Verwendung von compactMap.
Leogdion

6

Swift 2.2 Version

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

Rufen Sie grundsätzlich diese Methode auf, die eine zufällige Zeichenfolge mit der Länge der an die Funktion übergebenen Ganzzahl generiert. Um die möglichen Zeichen zu ändern, bearbeiten Sie einfach die Zeichenfolge stringString. Unterstützt auch Unicode-Zeichen.

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


2
Aus irgendeinem unglücklichen Grund gibt diese Version gelegentlich einenEXC_BAD_INSTRUCTION
Joe

Hey Joe, hast du einen Demo-Code, der diesen Fehler reproduzieren kann?
Ernest Cunningham

Lass mich sehen was ich machen kann; Ich habe es nur so genannt, wie es ist in einem IB-Action-Outlet mit let random = randomString(16). Das EXC war nur auf einem realen Gerät und ich habe es nicht in einem Simulator gesehen und es war zeitweise auf dem Gerät.
Joe

1
Siehe diese SO-Frage für den Grund, warum dies die halbe Zeit auf 32-Bit-Geräten abstürzt
julien_c

Wichtig: random % count nicht nicht (immer) schafft eine gleichmäßige Verteilung. Wenn dies für Sie relevant ist, suchen Sie nach anderen Antworten, die Sie verwenden arc4random_uniform().
Raphael

6

Für Leute, die nicht den gesamten Zeichensatz eingeben möchten:

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

für 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
Hast du diesen Code ausprobiert? Haben Sie bemerkt, dass die zurückgegebene Zeichenfolgenlänge falsch ist und nur Ziffern vorhanden sind? Schauen Sie sich stackoverflow.com/q/39566062/1187415 an , das das gleiche Problem hat.
Martin R

@ MartinR danke für den Hinweis. Ich habe meine Antwort aktualisiert
S1LENT WARRIOR

5

Ein reiner Swift-Zufall Stringvon jedem CharacterSet.

Verwendung: 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
    }
}

Die characters()Funktion ist meine schnellste bekannte Implementierung .


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

Meine noch schnellere Umsetzung der Frage:

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-frei, jedoch auf 43 Zeichen begrenzt. Wenn Sie mehr benötigen, kann es geändert werden. Dieser Ansatz hat zwei Vorteile gegenüber der alleinigen Verwendung einer UUID:

  1. Größere Entropie durch Verwendung von Kleinbuchstaben, da UUID()nur Großbuchstaben generiert werden
  2. A UUIDist höchstens 36 Zeichen lang (einschließlich der 4 Bindestriche), aber nur 32 Zeichen lang. Wenn Sie etwas länger benötigen oder keine Bindestriche möchten, können Sie dies mithilfe der base64EncodedStringHandles tun

Diese Funktion verwendet auch a UInt, um negative Zahlen zu vermeiden.

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

Aufruf in einer Schleife zur Überprüfung der Ausgabe:

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

Welches produziert:

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

Das Problem bei der Beantwortung von Fragen zu "Ich brauche zufällige Zeichenfolgen" (in welcher Sprache auch immer) ist, dass praktisch jede Lösung eine fehlerhafte primäre Spezifikation der Zeichenfolgenlänge verwendet . Die Fragen selbst zeigen selten, warum die zufälligen Zeichenfolgen benötigt werden, aber ich würde Sie herausfordern, dass Sie selten zufällige Zeichenfolgen mit einer Länge von beispielsweise 8 benötigen. Was Sie ausnahmslos benötigen, ist eine Anzahl eindeutiger Zeichenfolgen , die beispielsweise als Bezeichner für einen bestimmten Zweck verwendet werden sollen.

Es gibt zwei Möglichkeiten, streng eindeutige Zeichenfolgen zu erhalten: deterministisch (was nicht zufällig ist) und Speichern / Vergleichen (was belastend ist). Was machen wir? Wir geben den Geist auf. Wir gehen stattdessen mit probabilistischer Einzigartigkeit . Das heißt, wir akzeptieren, dass ein gewisses (jedoch geringes) Risiko besteht, dass unsere Saiten nicht eindeutig sind. Hier ist das Verständnis von Kollisionswahrscheinlichkeit und Entropie hilfreich.

Daher werde ich das unveränderliche Bedürfnis so umformulieren, dass einige Zeichenfolgen mit einem geringen Wiederholungsrisiko benötigt werden. Nehmen wir als konkretes Beispiel an, Sie möchten ein Potenzial von 5 Millionen IDs generieren. Sie möchten nicht jede neue Zeichenfolge speichern und vergleichen, und Sie möchten, dass sie zufällig ist, sodass Sie ein gewisses Wiederholungsrisiko akzeptieren. Nehmen wir zum Beispiel ein Risiko von weniger als 1 in einer Billion Wiederholungswahrscheinlichkeit. Also, welche Länge der Saite brauchst du? Nun, diese Frage ist nicht genau spezifiziert, da sie von den verwendeten Zeichen abhängt. Aber was noch wichtiger ist, es ist falsch. Was Sie brauchen, ist eine Angabe der Entropie der Saiten, nicht ihrer Länge. Die Entropie kann in direktem Zusammenhang mit der Wahrscheinlichkeit einer Wiederholung in einer bestimmten Anzahl von Zeichenfolgen stehen. Stringlänge kann nicht.

Und hier kann eine Bibliothek wie EntropyString helfen. So generieren Sie zufällige IDs mit einer Wahrscheinlichkeit von weniger als 1 in einer Billion Wiederholungen in 5 Millionen Zeichenfolgen mit EntropyString:

import EntropyString

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

"Rrrj6pN4d6GBrFLH4"

EntropyStringVerwendet standardmäßig einen Zeichensatz mit 32 Zeichen. Es gibt andere vordefinierte Zeichensätze, und Sie können auch Ihre eigenen Zeichen angeben. Beispiel: Generieren von IDs mit derselben Entropie wie oben, jedoch unter Verwendung von Hex-Zeichen:

import EntropyString

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

135fe71aec7a80c02dce5

Beachten Sie den Unterschied in der Zeichenfolgenlänge aufgrund des Unterschieds in der Gesamtzahl der Zeichen im verwendeten Zeichensatz. Das Risiko einer Wiederholung in der angegebenen Anzahl potenzieller Zeichenfolgen ist gleich. Die Stringlängen sind nicht. Und das Beste ist, dass das Wiederholungsrisiko und die potenzielle Anzahl von Zeichenfolgen explizit sind. Kein Raten mehr mit Stringlänge.


2

Wenn Ihre zufällige Zeichenfolge sicher-zufällig sein soll, verwenden Sie Folgendes:

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

Wenn Sie nur eine eindeutige Kennung benötigen, UUID().uuidStringkann dies Ihren Zwecken dienen.


1

Aktualisiert für Swift 4. Verwenden Sie eine verzögert gespeicherte Variable für die Klassenerweiterung. Dies wird nur einmal berechnet.

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

Verwendung von RandomNumberGenerator für eine bessere Leistung als Apple-Empfehlung

Verwendung: String.random(20) Ergebnis: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

Dies ist die Swift -est Lösung , die ich tun konnte. 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
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.