Tạo chuỗi ký tự chữ và số ngẫu nhiên trong Swift


208

Làm cách nào tôi có thể tạo chuỗi ký tự chữ và số ngẫu nhiên trong Swift?

Câu trả lời:


354

Cập nhật Swift 4.2

Swift 4.2 đã giới thiệu những cải tiến lớn trong việc xử lý các giá trị và các yếu tố ngẫu nhiên. Bạn có thể đọc thêm về những cải tiến ở đây . Đây là phương pháp rút gọn thành một vài dòng:

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

Cập nhật 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
}

Câu trả lời gốc:

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
Có cách nào tôi có thể sửa đổi ở trên để đảm bảo rằng chuỗi ký tự chữ và số được tạo chỉ dài 6 hoặc 8 ký tự không?
ksa_coder

4
RandomString (chiều dài: 6) hoặc RandomString (chiều dài: 8)
Simon H

58

Đây là một giải pháp sẵn sàng sử dụng theo cú pháp Swiftier . Bạn chỉ có thể sao chép và dán nó:

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
}

Nếu bạn thích một Framework cũng có một số tính năng tiện dụng hơn thì hãy kiểm tra dự án của tôi HandySwift . Nó cũng bao gồm một giải pháp đẹp cho các chuỗi chữ và số ngẫu nhiên :

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

49

Bạn cũng có thể sử dụng nó theo cách sau:

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

Cách sử dụng đơn giản:

let randomString = String.random()

Cú pháp 3 Swift:

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

Cú pháp 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

CẬP NHẬT 2019.

Trong trường hợp bất thường đó

vấn đề hiệu suất.

Đây là một chức năng cực kỳ rõ ràng mà lưu trữ :

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

Điều này là khi bạn có một bộ ký tự cố định, đã biết .

Mẹo tiện dụng:

Lưu ý rằng "abcdefghjklmnpqrstuvwxyz12345789" tránh các ký tự 'xấu'

Không có 0, o, O, i, v.v ... các nhân vật con người thường nhầm lẫn.

Điều này thường được thực hiện để đặt mã và các mã tương tự mà khách hàng của con người sẽ sử dụng.


1
Nâng cao cho repeating:count:.
Cœur

10

Đơn giản và nhanh chóng - UUID (). UuidString

// Trả về một chuỗi được tạo từ UUID, chẳng hạn như "E621E1F8-C36C-495A-93FC-0C247A3E6E5F"

công khai var uuidString: Chuỗi {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

BIÊN TẬP

Xin đừng nhầm lẫn với UIDevice.current.identifierForVendor?.uuidStringnó sẽ không cung cấp giá trị ngẫu nhiên.


10

Với Swift 4.2, cách tốt nhất của bạn là tạo một chuỗi với các ký tự bạn muốn và sau đó sử dụng RandomEuity để chọn từng ký tự:

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

Tôi chi tiết hơn về những thay đổi ở đây .


3
Thay vì bản đồ, bạn có thể sử dụng compactMap và sau đó không cần! nhà điều hành. ;)
Kristaps Grinbergs

1
Xin chào @KristapsGrinbergs! Tôi nghĩ rằng việc hủy ghép buộc sẽ có hiệu suất tốt hơn so với sử dụng compactMap.
leogdion

6

Phiên bản 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
}

Về cơ bản gọi phương thức này sẽ tạo ra một chuỗi ngẫu nhiên độ dài của số nguyên được trao cho hàm. Để thay đổi các ký tự có thể, chỉ cần chỉnh sửa chuỗi characterString. Hỗ trợ các ký tự unicode quá.

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


2
Vì một số lý do không may, phiên bản này thỉnh thoảng đưa ra mộtEXC_BAD_INSTRUCTION
Joe

Này Joe, bạn có mã demo nào có thể tái tạo lỗi này không?
Ernest Cickyham

Hãy để tôi xem những gì tôi có thể làm; Tôi chỉ gọi nó như là trong một cửa hàng hành động IB với let random = randomString(16). EXC chỉ có trên một thiết bị thực và tôi đã không nhìn thấy nó trong một trình giả lập và nó không liên tục trên thiết bị.
Joe

1
Xem câu hỏi SO này để biết lý do tại sao điều này bị treo một nửa thời gian trên các thiết bị 32 bit: stackoverflow.com/questions/25274265/iêu
julien_c

Chú ý: random % count không không (luôn luôn) tạo ra một phân bố đều. Nếu điều này có liên quan đến bạn, hãy tìm đến những câu trả lời khác sử dụng arc4random_uniform().
Raphael

6

Dành cho những người không muốn gõ toàn bộ bộ ký tự:

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

cho 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
Bạn đã thử mã đó chưa? Bạn có nhận thấy rằng độ dài chuỗi trả về là sai và chỉ có các chữ số không? Hãy xem stackoverflow.com/q/39566062/1187415 , có cùng một vấn đề.
Martin R

@MartinR cảm ơn bạn đã chỉ ra điều đó. Tôi đã cập nhật câu trả lời của mình
WARLOR S1LENT

5

Một Swift ngẫu nhiên thuần túy Stringtừ bất kỳ CharacterSet.

Sử dụng: 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
    }
}

Các characters()chức năng là thực hiện được biết đến nhanh nhất của tôi .


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

Việc thực hiện Swift-ier thậm chí nhiều hơn của tôi về câu hỏi:

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

Vòng lặp miễn phí, mặc dù nó được giới hạn trong 43 ký tự. Nếu bạn cần nhiều hơn, nó có thể được sửa đổi. Cách tiếp cận này có hai ưu điểm so với chỉ sử dụng UUID:

  1. Entropy lớn hơn bằng cách sử dụng chữ cái viết thường, vì UUID()chỉ tạo chữ cái viết hoa
  2. A UUIDdài tối đa 36 ký tự (bao gồm 4 dấu gạch nối), nhưng chỉ dài 32 ký tự mà không có. Nếu bạn cần một cái gì đó lâu hơn, hoặc không muốn có dấu gạch nối, việc sử dụng base64EncodedStringtay cầm này

Ngoài ra, hàm này sử dụng a UIntđể tránh các số âm.

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

Gọi nó trong một vòng lặp để kiểm tra đầu ra:

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

Sản xuất:

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

Vấn đề với các câu trả lời cho câu hỏi "Tôi cần chuỗi ngẫu nhiên" (bằng bất kỳ ngôn ngữ nào) thực tế là mọi giải pháp đều sử dụng một đặc tả chính thiếu sót về độ dài chuỗi . Các câu hỏi hiếm khi tiết lộ lý do tại sao các chuỗi ngẫu nhiên là cần thiết, nhưng tôi sẽ thách thức bạn hiếm khi cần các chuỗi có độ dài ngẫu nhiên, nói 8. Điều bạn luôn cần là một số chuỗi duy nhất , ví dụ, để sử dụng làm định danh cho mục đích nào đó.

Có hai cách hàng đầu để có được các chuỗi duy nhất nghiêm ngặt : xác định (không ngẫu nhiên) và lưu trữ / so sánh (đó là rất khó). Chúng ta làm gì? Chúng tôi từ bỏ con ma. Chúng tôi đi với sự độc đáo xác suất thay thế. Đó là, chúng tôi chấp nhận rằng có một số rủi ro (dù nhỏ) rằng chuỗi của chúng tôi sẽ không phải là duy nhất. Đây là nơi hiểu xác suất va chạmentropy là hữu ích.

Vì vậy, tôi sẽ định nghĩa lại nhu cầu bất biến là cần một số chuỗi có rủi ro lặp lại nhỏ. Ví dụ cụ thể, giả sử bạn muốn tạo tiềm năng 5 triệu ID. Bạn không muốn lưu trữ và so sánh từng chuỗi mới và bạn muốn chúng là ngẫu nhiên, vì vậy bạn chấp nhận một số rủi ro lặp lại. Ví dụ: giả sử rủi ro ít hơn 1 trong một nghìn tỷ cơ hội lặp lại. Vậy bạn cần độ dài của chuỗi? Vâng, câu hỏi đó không được xác định rõ vì nó phụ thuộc vào các ký tự được sử dụng. Nhưng quan trọng hơn, đó là sai lầm. Những gì bạn cần là một đặc điểm kỹ thuật của entropy của chuỗi, không phải độ dài của chúng. Entropy có thể liên quan trực tiếp đến xác suất lặp lại trong một số chuỗi. Độ dài chuỗi không thể.

Và đây là nơi một thư viện như EntropyString có thể giúp đỡ. Để tạo ID ngẫu nhiên có ít hơn 1 trong một nghìn tỷ cơ hội lặp lại trong 5 triệu chuỗi bằng cách sử dụng EntropyString:

import EntropyString

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

"Rrrj6pN4d6GBrFLH4"

EntropyStringsử dụng một bộ ký tự với 32 ký tự theo mặc định. Có các bộ ký tự được xác định trước khác và bạn cũng có thể chỉ định các ký tự của riêng mình. Ví dụ: tạo ID có cùng entropy như trên nhưng sử dụng các ký tự hex:

import EntropyString

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

"135fe71aec7a80c02dce5"

Lưu ý sự khác biệt về độ dài chuỗi do sự khác biệt về tổng số ký tự trong bộ ký tự được sử dụng. Nguy cơ lặp lại trong số lượng các chuỗi tiềm năng được chỉ định là như nhau. Độ dài chuỗi không. Và tốt nhất, nguy cơ lặp lại và số chuỗi tiềm năng là rõ ràng. Không còn phải đoán với độ dài chuỗi.


2

Nếu chuỗi ngẫu nhiên của bạn phải an toàn-ngẫu nhiên, hãy sử dụng:

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

Nếu bạn chỉ cần một định danh duy nhất, UUID().uuidStringcó thể phục vụ mục đích của bạn.


1

Đã cập nhật cho Swift 4. Sử dụng biến được lưu trữ lười biếng trên phần mở rộng lớp. Điều này chỉ được tính một lần.

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

Chuyển 4

Sử dụng RandomNumberGenerator để có hiệu suất tốt hơn như khuyến nghị của Apple

Cách sử dụng: String.random(20) Kết quả: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

Đây là Swift giải pháp -est tôi có thể đưa ra. 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
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.