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

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

127143 次浏览

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

这里有一个现成的解决方案更迅捷的语法。你可以简单地复制粘贴它:

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"

我的甚至更迅捷实现的问题:

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

你也可以这样使用它:

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

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
}

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

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

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

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

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
}

这是我能想出的斯威夫特-est解决方案。斯威夫特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
}
}

来自任意CharacterSet的纯Swift随机String

用法: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()函数是我最快的实现

更新后的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等等…人类经常混淆的字符。

这通常用于预订代码和人类客户将使用的类似代码。

__abc0——__abc1

//返回由UUID创建的字符串,例如&;e621e1f8 - c36c - 495a - 93fc - 0c247a3e6e5f &;

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不会给出随机值。

迅速:

let randomString = NSUUID().uuidString

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

有两种主要的方法来获取严格独特字符串:确定性(它不是随机的)和存储/比较(它是繁重的)。我们该怎么办?我们放弃了。我们用概率的独特性代替。也就是说,我们接受存在一些(无论多么小)的风险,即我们的字符串不是唯一的。这就是理解< em > < / em >碰撞概率熵< em > < / em >有帮助的地方。

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

这就是像EntropyString这样的库可以帮助的地方。使用EntropyString生成在500万个字符串中重复的概率小于万亿分之一的随机id:

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)

“135 fe71aec7a80c02dce5”

请注意由于所使用的字符集中字符总数的不同而导致的字符串长度的差异。在指定数量的潜在字符串中重复的风险相同。字符串长度不是。最重要的是,重复的风险和字符串的潜在数量是明确的。没有更多的猜测字符串长度。

如果你的随机字符串应该是安全随机的,使用这个:

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
}

使用斯威夫特4.2,最好的方法是用你想要的字符创建一个字符串,然后使用randomElement来选择每个字符:

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

我详细介绍了这些变化在这里

为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

免费循环,尽管它被限制在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

斯威夫特4

苹果推荐使用RandomNumberGenerator来获得更好的性能

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

一种避免输入整套字符的方法:

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

SwifterSwift有这个实现

/// SwifterSwift: Create a new random string of given length.
///
///     String(randomOfLength: 10) -> "gY8r3MHvlQ"
///
/// - Parameter length: number of characters in string.
init(randomOfLength length: Int) {
guard length > 0 else {
self.init()
return
}


let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var randomString = ""
for _ in 1...length {
randomString.append(base.randomElement()!)
}
self = randomString
}

我做了一些改变,并使用这个实现

static func random(randomOfLength length: Int) -> String {
guard length > 0 else { return "" }
let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var randomString = ""
for _ in 1...length {
guard let randomCharacter = base.randomElement() else { continue }
randomString.append(randomCharacter)
}
return randomString
}

斯威夫特5.6

此函数生成一个以36为基数的10位数字,然后将其作为字母数字字符串返回。

func randomCode(length: Int) -> String {
let radix = 36 // = 10 digits + 26 letters
let number = Int.random(in: 0..<(pow(radix, length)))
return String(number, radix: radix, uppercase: true)
}

或者如果你不希望代码以“"0"”开头:

func randomCode(length: Int) -> String {
let radix = 36 // = 10 digits + 26 letters
let range = (pow(radix, length)/2)..<(pow(radix, length))
let number = Int.random(in: range)
return String(number, radix: radix, uppercase: true)
}