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

283

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

27个回答

485

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
5
randomString(length:6) 或 randomString(length:8)意思是生成一个长度为6或8的随机字符串。 - Simon Hessner
1
这个是否具有密码学安全性? - Peter Schorn

64

这是一个使用更加简洁的Swift语法的现成解决方案。您只需复制并粘贴即可:

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
}

如果您更喜欢一个还具有一些方便功能的框架,请随时查看我的项目HandySwift。它还包括一个美丽的随机字母数字字符串解决方案

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

53

您也可以按照以下方式使用:

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

2021年无法正常工作。 - Richard Topchii
1
@RichardTopchii 你能澄清一下"2021"是指什么吗?使用特定的Swift版本来表达不兼容性比使用年份更清楚明确。 - undefined
它绝对不适用于Swift 5.9。 - undefined

40

Swift:

let randomString = NSUUID().uuidString

UUID().uuidString现在。 - Mark Bridges
2
UUID有时会给出相同的字符串! - Phd. Burak Öztürk
3
有不同种类的UUID,其中一些是基于时间的。Swift Foundation中使用的是V4,随机生成的。几乎没有机会(就像极少)会生成相同的UUID。 - Robin Daugherty
请注意,这不会生成完全的字母数字字符串,因为UUID仅限于0-9 A-F字符范围。 - Cristik

18

简单快速 -- UUID().uuidString

// 返回由 UUID 创建的字符串,例如“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

编辑

请不要将其与UIDevice.current.identifierForVendor?.uuidString混淆,它不会提供随机值。


1
请注意,这不会生成完全的字母数字字符串,因为UUID仅限于0-9 A-F字符范围。 - Cristik

16

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: 点赞。 - Cœur
测试中的性能表现。这个算法真他妈的慢。只比使用letters.randomElement()的答案快5%! - bodich
@bodich无论如何,在讨论的环境中,性能都不可能起到任何作用。在应用程序中,您可能需要生成这样的代码(例如用于登录或类似的操作),也许在应用程序的生命周期中只需生成一次。请注意,如果(出于无法想象的原因)您必须每秒生成这样的代码一次,那么...性能仍然是一个绝对不重要的问题。编程时专注于性能是一个巨大的错误。制作应用程序时,您只需要关注代码的可重用性、代码的简洁性、代码的可靠性以及代码的成本... - Fattie
在极其罕见的情况下,如果有人正在进行科学编程或类似的工作,也许是使用服务器端的Swift语言,并且由于某种无法想象的原因,你需要每秒处理数以亿计的字符串,并且要求实时性非常高,那么,所采取的方法将与这里提到的解决方案完全不同,你明白吗? - Fattie
谢谢你指出我在回答中表达不清楚关于性能的部分,已经进行了修改! - Fattie

14

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)

很高兴能够控制字符串长度。谢谢。 - Rakshitha Muranga Rodrigo
@RakshithaMurangaRodrigo 欢迎加入,我们必须感谢Google。 - Sreekanth G
这是几个早期针对Swift 4.2的答案的重复。这对于Swift 5来说并不新鲜。 - undefined

13

使用 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

9
避免输入整个字符集的方法:
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)
}

7

这种方法虽然长度限制为43个字符,但是它可以避免循环。如果需要更多字符,可以进行修改。与仅使用UUID相比,这种方法有两个优点:

  1. 使用小写字母来增加熵,因为 UUID()仅生成大写字母
  2. UUID最长只能达到36个字符(包括4个连字符),但不带连字符时只有32个字符。如果需要更长的字符串或不想包含连字符,则使用base64EncodedString即可处理

此外,这个函数利用了一个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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接