Générer une chaîne alphanumérique aléatoire dans Swift


208

Comment puis-je générer une chaîne alphanumérique aléatoire dans Swift?

Réponses:


355

Mise à jour Swift 4.2

Swift 4.2 a introduit des améliorations majeures dans le traitement des valeurs et des éléments aléatoires. Vous pouvez en savoir plus sur ces améliorations ici . Voici la méthode réduite à quelques lignes:

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

Mise à jour 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
}

Réponse originale:

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
Existe-t-il un moyen de modifier ce qui précède pour garantir que la chaîne alphanumérique générée ne comporte que 6 ou 8 caractères?
ksa_coder

4
randomString (durée: 6) ou randomString (durée: 8)
Simon H

58

Voici une solution prête à l'emploi dans la syntaxe Swiftier . Vous pouvez simplement le copier-coller:

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
}

Si vous préférez un Framework qui possède également des fonctionnalités plus pratiques, n'hésitez pas à consulter mon projet HandySwift . Il comprend également une belle solution pour les chaînes alphanumériques aléatoires :

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

49

Vous pouvez également l'utiliser de la manière suivante:

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

Utilisation simple:

let randomString = String.random()

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

Syntaxe de 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

Avec Swift 4.2, votre meilleur pari est de créer une chaîne avec les caractères que vous souhaitez, puis d'utiliser randomElement pour choisir chaque caractère:

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

Je détaille plus sur ces changements ici .


3
Au lieu de la carte, vous pouvez utiliser compactMap et alors il n'y a pas besoin de! opérateur. ;)
Kristaps Grinbergs

1
Salut @KristapsGrinbergs! Je pensais que le déballage forcé aurait de meilleures performances que l'utilisation de compactMap.
leogdion

11

MISE À JOUR 2019.

Dans le cas inhabituel

la performance compte.

Voici une fonction extrêmement claire qui met en cache :

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

C'est pour quand vous avez un jeu de caractères fixe et connu .

Conseil pratique:

Notez que «abcdefghjklmnpqrstuvwxyz12345789» évite les «mauvais» caractères

Il n'y a pas de 0, o, O, i, etc ... les personnages confondent souvent les humains.

Cela est souvent fait pour les codes de réservation et les codes similaires que les clients humains utiliseront.


1
Vote pour repeating:count:.
Cœur

10

Simple et rapide - UUID (). UuidString

// Renvoie une chaîne créée à partir de l'UUID, telle que "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

ÉDITER

Veuillez ne pas confondre avec UIDevice.current.identifierForVendor?.uuidStringcela ne donnera pas de valeurs aléatoires.


6

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

Appelez essentiellement cette méthode qui générera une chaîne aléatoire de la longueur de l'entier remis à la fonction. Pour modifier les caractères possibles, modifiez simplement la chaîne de caractères de chaîne. Prend également en charge les caractères unicode.

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


2
Pour une raison malheureuse, cette version donne parfois unEXC_BAD_INSTRUCTION
Joe

Hé Joe, avez-vous un code de démonstration qui peut reproduire cette erreur?
Ernest Cunningham

Laisse moi voir ce que je peux faire; Je l'appelais seulement tel quel dans une sortie d'action IB avec let random = randomString(16). L'EXC n'était que sur un vrai appareil et je ne l'ai pas vu dans un simulateur et il était intermittent sur l'appareil.
Joe

1
Voir cette question SO pour la raison pour laquelle cela se bloque la moitié du temps sur les appareils 32 bits: stackoverflow.com/questions/25274265/…
julien_c

Important: random % count ne crée pas (toujours) une distribution uniforme. Si cela vous concerne, recherchez d'autres réponses utiles arc4random_uniform().
Raphael

6

Pour les gens qui ne veulent pas taper l'ensemble complet des caractères:

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

pour 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
Avez-vous essayé ce code? Avez-vous remarqué que la longueur de chaîne renvoyée est incorrecte et qu'il n'y a que des chiffres? Jetez un œil à stackoverflow.com/q/39566062/1187415 , qui a le même problème.
Martin R

@MartinR merci de l'avoir signalé. j'ai mis à jour ma réponse
S1LENT WARRIOR

5

Un Swift pur aléatoire Stringde tout CharacterSet.

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

La characters()fonction est mon implémentation la plus rapide connue .


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

Ma mise en œuvre encore plus rapide de la question:

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

Sans boucle, bien qu'il soit limité à 43 caractères. Si vous en avez besoin de plus, il peut être modifié. Cette approche présente deux avantages par rapport à l'utilisation exclusive d'un UUID:

  1. Entropie supérieure en utilisant des lettres minuscules, car UUID()ne génère que des lettres majuscules
  2. A UUIDcomporte au maximum 36 caractères (y compris les 4 tirets), mais seulement 32 caractères sans. Si vous avez besoin de quelque chose de plus long ou si vous ne voulez pas de tirets inclus, l'utilisation des base64EncodedStringpoignées

De plus, cette fonction utilise un UIntpour éviter les nombres négatifs.

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

L'appeler en boucle pour vérifier la sortie:

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

Ce qui produit:

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

Le problème avec les réponses aux questions "J'ai besoin de chaînes aléatoires" (dans n'importe quelle langue) est que pratiquement chaque solution utilise une spécification primaire erronée de longueur de chaîne . Les questions elles-mêmes révèlent rarement pourquoi les chaînes aléatoires sont nécessaires, mais je vous mets au défi que vous ayez rarement besoin de chaînes aléatoires de longueur, disons 8. Ce dont vous avez invariablement besoin, c'est d'un certain nombre de chaînes uniques , par exemple, à utiliser comme identificateurs dans un certain but.

Il existe deux façons principales d'obtenir des chaînes strictement uniques : de manière déterministe (qui n'est pas aléatoire) et de stocker / comparer (ce qui est onéreux). Qu'est-ce qu'on fait? Nous abandonnons le fantôme. Nous optons plutôt pour l' unicité probabiliste . Autrement dit, nous acceptons qu'il existe un risque (aussi faible soit-il) que nos cordes ne soient pas uniques. C'est là que la compréhension de la probabilité de collision et de l' entropie est utile.

Je vais donc reformuler le besoin invariable comme nécessitant un certain nombre de chaînes avec un petit risque de répétition. À titre d'exemple concret, supposons que vous souhaitiez générer un potentiel de 5 millions d'ID. Vous ne voulez pas stocker et comparer chaque nouvelle chaîne et vous voulez qu'elles soient aléatoires, vous acceptez donc un risque de répétition. Par exemple, disons un risque de moins de 1 sur mille milliards de chances de répétition. Alors, quelle longueur de chaîne avez-vous besoin? Eh bien, cette question est sous-spécifiée car elle dépend des caractères utilisés. Mais plus important encore, c'est erroné. Ce dont vous avez besoin est une spécification de l'entropie des cordes, pas de leur longueur. L'entropie peut être directement liée à la probabilité de répétition dans un certain nombre de chaînes. La longueur de chaîne ne peut pas.

Et c'est là qu'une bibliothèque comme EntropyString peut vous aider. Pour générer des ID aléatoires qui ont moins de 1 chance sur 1 000 milliards de répétitions dans 5 millions de chaînes en utilisant EntropyString:

import EntropyString

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

"Rrrj6pN4d6GBrFLH4"

EntropyStringutilise un jeu de caractères avec 32 caractères par défaut. Il existe d'autres jeux de caractères prédéfinis et vous pouvez également spécifier vos propres caractères. Par exemple, générer des ID avec la même entropie que ci-dessus mais en utilisant des caractères hexadécimaux:

import EntropyString

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

"135fe71aec7a80c02dce5"

Notez la différence de longueur de chaîne en raison de la différence du nombre total de caractères dans le jeu de caractères utilisé. Le risque de répétition dans le nombre spécifié de chaînes potentielles est le même. Les longueurs de chaîne ne le sont pas. Et surtout, le risque de répétition et le nombre potentiel de chaînes est explicite. Plus besoin de deviner avec la longueur de la chaîne.


2

Si votre chaîne aléatoire doit être sécurisée-aléatoire, utilisez ceci:

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

Si vous avez juste besoin d'un identifiant unique, cela UUID().uuidStringpeut servir vos objectifs.


1

Mis à jour pour Swift 4. Utilisez une variable stockée paresseuse sur l'extension de classe. Cela n'est calculé qu'une seule fois.

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

Utilisation de RandomNumberGenerator pour de meilleures performances comme recommandation Apple

Utilisation: String.random(20) Résultat: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

Ceci est la Swift solution -est je pouvais trouver. 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
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.