在Swift中生成随机字母数字字符串


208

如何在Swift中生成随机的字母数字字符串?

Answers:


355

Swift 4.2更新

Swift 4.2在处理随机值和元素方面进行了重大改进。您可以在此处阅读有关这些改进的更多信息。这是减少到几行的方法:

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

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
}

原始答案:

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
有什么办法可以修改上面的内容,以确保生成的字母数字字符串只有6个或8个字符长?
ksa_coder

4
randomString(length:6)或randomString(length:8)
Simon H

58

这是Swiftier语法中现成的解决方案。您可以简单地复制并粘贴它:

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
}

如果您喜欢还具有更多便捷功能的Framework,请随时签出我的项目HandySwift。它还包括一个针对随机字母数字字符串的漂亮解决方案

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

49

您也可以通过以下方式使用它:

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

简单用法:

let randomString = String.random()

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

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

更新于2019。

在不寻常的情况下

性能很重要。

这是一个非常清晰的缓存功能:

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

这适用于您拥有固定的已知字符集的情况。

方便提示:

请注意,“ abcdefghjklmnpqrstuvwxyz12345789”避免使用“错误”字符

没有0,o,o,i等...人类经常混淆的字符。

通常对预订代码和人类客户将使用的类似代码执行此操作。


1
正在为投票repeating:count:
心教堂

10

简单快速的 - 。UUID()uuidString

//返回从UUID创建的字符串,例如“ E621E1F8-C36C-495A-93FC-0C247A3E6E5F”

public var uuidString:字符串{get}

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

斯威夫特3.0

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

编辑

请不要 UIDevice.current.identifierForVendor?.uuidString混淆不会给出随机值。


10

使用Swift 4.2,最好的选择是使用所需字符创建一个字符串,然后使用randomElement选择每个字符:

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

我将在此处详细介绍这些更改。


3
您可以使用compactMap代替map,然后就不需要了!操作员。;)
Kristaps Grinbergs

1
嘿@KristapsGrinbergs!我的想法是,强制展开比使用compactMap具有更好的性能。
leogdion

6

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
}

基本上调用此方法将生成随机字符串,该字符串的长度为传递给该函数的整数。要更改可能的字符,只需编辑characterString字符串。也支持unicode字符。

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


2
由于某些不幸的原因,此版本有时会给EXC_BAD_INSTRUCTION
Joe

嗨,乔,您有演示代码可以重现此错误吗?
欧内斯特·坎宁安

让我看看我能做什么;我只是在IB操作出口中使用来原样调用它let random = randomString(16)。EXC仅在真实设备上,我在模拟器中看不到它,并且在设备上是间歇性的。

1
见这太问题的原因,这种崩溃一半的时间在32位器件:stackoverflow.com/questions/25274265/...
julien_c

重要提示: random % count(总是)创建一个均匀分布。如果这与您有关,请查找使用的其他答案arc4random_uniform()
拉斐尔

6

对于不想输入整个字符集的人:

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

对于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
您是否尝试过该代码?您是否注意到返回的字符串长度错误,并且只有数字?看一下stackoverflow.com/q/39566062/1187415,它也有同样的问题。
马丁R

@MartinR感谢您指出这一点。我已经更新了答案
S1LENT WARRIOR 16/09/19

5

纯斯威夫特随机String从所有CharacterSet

用法: 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
    }
}

characters()函数是我最快已知的实现


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

我对这个问题的更快捷的实现:

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

无循环,但限制为43个字符。如果需要更多,可以对其进行修改。与仅使用UUID相比,此方法有两个优点:

  1. 通过使用小写字母来增强熵,因为UUID()仅生成大写字母
  2. A的UUID长度最多为36个字符(包括4个连字符),但没有长度则只有32个字符。如果您需要更长的时间,或者不想包含连字符,请使用此base64EncodedString句柄

同样,此函数利用a UInt来避免负数。

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

循环调用以检查输出:

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

产生:

Nzk3NjgzMTdBQ0FBNDFCNzk2MDRENzZF
MUI5RURDQzE1RTdCNDA3RDg2MTI4QkQx
M0I3MjJBRjVFRTYyNDFCNkI5OUM1RUVC
RDA1RDZGQ0IzQjI1NDdGREI3NDgxM0Mx
NjcyNUQyOThCNzhCNEVFQTk1RTQ3NTIy
MDkwRTQ0RjFENUFGNEFDOTgyQTUxODI0
RDU2OTNBOUJGMDE4NDhEODlCNEQ1NjZG
RjM2MTUxRjM4RkY3NDU2OUFDOTI0Nzkz
QzUwOTE1N0U1RDVENDE4OEE5NTM2Rjcy
Nzk4QkMxNUJEMjYwNDJDQjhBQkY5QkY5
ODhFNjU0MDVEMUI2NEI5QUIyNjNCNkVF

3

斯威夫特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

回答“我需要随机字符串”问题(无论使用哪种语言)的问题实际上是每个解决方案都使用有缺陷的字符串长度主要规范。问题本身很少揭示为什么需要随机字符串,但是我会挑战您,很少需要长度为8的随机字符串。例如,您总是需要一定数量的唯一字符串,例如,出于某些目的用作标识符。

获得严格唯一的字符串有两种主要方法:确定性(不是随机的)和存储/比较(繁琐的)。我们做什么?我们放弃了幽灵。我们代之以概率唯一性。也就是说,我们接受我们的字符串存在唯一性的风险(但是很小)。在这里,了解碰撞概率很有帮助。

因此,我将不变的需求重新表述为需要一定数量的字符串,重复的风险很小。举一个具体的例子,假设您要生成500万个ID。您不想存储和比较每个新字符串,并且希望它们是随机的,因此您会承受重复的风险。例如,假设万亿重覆机会的风险小于1。那么,您需要多长的字符串?嗯,这个问题没有明确说明,因为它取决于所使用的字符。但更重要的是,它被误导了。您需要的是字符串熵的规范,而不是字符串的长度。熵可以直接与某些字符串中重复的概率相关。字符串长度不能。

这就是像EntropyString这样的库可以提供帮助的地方。要生成随机ID,该随机ID在500万个字符串中重复的可能性小于1万亿分之一,请使用EntropyString

import EntropyString

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

“ Rrrj6pN4d6GBrFLH4”

EntropyString默认情况下使用32个字符的字符集。还有其他预定义的字符集,您也可以指定自己的字符。例如,生成具有与上述相同的熵但使用十六进制字符的ID:

import EntropyString

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

“ 135fe71aec7a80c02dce5”

请注意,由于使用的字符集中的字符总数不同,因此字符串长度也有所不同。在指定数量的潜在字符串中重复的风险是相同的。字符串长度不是。最重要的是,重复的风险和潜在的字符串数是明确的。不再需要猜测字符串的长度。


2

如果您的随机字符串应该是安全随机的,请使用以下命令:

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

如果您只需要一个唯一的标识符,UUID().uuidString则可以满足您的目的。


1

已为Swift 4更新。在类扩展名上使用延迟存储的变量。这仅被计算一次。

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

按照Apple的建议使用RandomNumberGenerator以获得更好的性能

用法:String.random(20) 结果: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

这是我能想到的最迅速的解决方案。斯威夫特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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.