Відповіді:
Оновлення Swift 4.2
Swift 4.2 представив основні вдосконалення в роботі зі випадковими значеннями та елементами. Більше про ці вдосконалення ви можете прочитати тут . Ось метод, зведений до кількох рядків:
func randomString(length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..<length).map{ _ in letters.randomElement()! })
}
Швидке оновлення 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
}
Ось готове до використання рішення у синтаксисі 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"
Ви можете використовувати його також наступним чином:
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
}
}
Швидкий:
let randomString = NSUUID().uuidString
У незвичному випадку це
Ось надзвичайно чітка функція, яка кешує :
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)
}
Це для тих випадків, коли у вас є фіксований, відомий набір символів.
Зручна порада:
Немає 0, о, О, я і т. Д. ... символи, які люди часто плутають.
Це часто робиться для кодів бронювання та подібних кодів, якими користуватимуться людські клієнти.
repeating:count:
.
Простий і швидкий - UUID (). UuidString
// Повертає рядок, створений з UUID, наприклад "E621E1F8-C36C-495A-93FC-0C247A3E6E5F"
public var uuidString: String {get}
Swift 3.0
let randomString = UUID().uuidString //0548CD07-7E2B-412B-AD69-5B2364644433
print(randomString.replacingOccurrences(of: "-", with: ""))
//0548CD077E2B412BAD695B2364644433
EDIT
Будь ласка , не плутайте з UIDevice.current.identifierForVendor?.uuidString
нею не даватиме випадкові значення.
Завдяки Swift 4.2 найкраще створити рядок з потрібними символами, а потім використовувати randomElement для вибору кожного символу:
let length = 32
let characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomCharacters = (0..<length).map{_ in characters.randomElement()!}
let randomString = String(randomCharacters)
Я детальніше про ці зміни тут .
Версія 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
}
В основному виклик цього методу, який буде генерувати випадкову рядок довжиною цілого числа, переданого функції. Для зміни можливих символів просто відредагуйте рядок символівСтринг. Також підтримуються символи Unicode.
https://gist.github.com/gingofthesouth/54bea667b28a815b2fe33a4da986e327
EXC_BAD_INSTRUCTION
let random = randomString(16)
. EXC був лише на реальному пристрої, і я не бачив його в тренажері, і він переривався на пристрої.
random % count
це НЕ (завжди) створюють однорідний розподіл. Якщо це стосується вас, перегляньте інші відповіді, які використовують arc4random_uniform()
.
Для людей, які не хочуть набирати весь набір символів:
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)
}
для 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
}
Чистий Swift випадковий 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()
Функція мій найшвидший з відомих реалізації .
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 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("")
}
Без циклу, хоча він обмежений 43 символами. Якщо вам потрібно більше, його можна змінити. Цей підхід має дві переваги перед виключно використанням UUID:
UUID()
створює лише великі літери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
Швидкий 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)
Проблема з відповідями на запитання "Мені потрібні випадкові рядки" (будь-якою мовою) практично в кожному рішенні використовується хибна первинна специфікація довжини рядка . Самі запитання рідко виявляють, для чого потрібні випадкові рядки, але я б заперечував, що вам рідко потрібні випадкові рядки довжиною, скажімо 8. Те, що вам незмінно потрібно, це деяка кількість унікальних рядків , наприклад, щоб використовувати як ідентифікатори для певної мети.
Є два провідні способи отримання строго унікальних рядків: детерміновано (що не випадково) та зберігати / порівнювати (що є обтяжливим). Що ми робимо? Ми відмовляємося від привида. Натомість ми йдемо з імовірнісною унікальністю . Тобто ми приймаємо, що існує певний (хоча і малий) ризик того, що наші струни не будуть унікальними. Тут допомагають розуміння ймовірності зіткнення та ентропії .
Тож я перефразую незмінну потребу як потрібну деяку кількість рядків з невеликим ризиком повторити. В якості конкретного прикладу, скажімо, ви хочете створити потенціал у 5 мільйонів ідентифікаторів. Ви не хочете зберігати та порівнювати кожен новий рядок, а ви хочете, щоб вони були випадковими, тому ви приймаєте певний ризик повторення. Наприклад, скажімо, ризик менший ніж 1 на трильйон шансів повторити. Отже, яка довжина струни вам потрібна? Ну, це питання не визначено, оскільки це залежить від використовуваних персонажів. Але що ще важливіше - це помилково. Вам потрібно конкретизувати ентропію струн, а не їх довжину. Ентропія може бути безпосередньо пов'язана з ймовірністю повторення в деякій кількості рядків. Довжина рядка не може.
І тут може допомогти бібліотека на зразок EntropyString . Для створення випадкових ідентифікаторів, які мають менше 1 трильйона шансів повторити в 5 мільйонах рядків, використовуючи EntropyString
:
import EntropyString
let random = Random()
let bits = Entropy.bits(for: 5.0e6, risk: 1.0e12)
random.string(bits: bits)
"Rrrj6pN4d6GBrFLH4"
EntropyString
використовує набір символів з 32 символами за замовчуванням. Є й інші заздалегідь задані набори символів, і ви можете також вказати власні символи. Наприклад, генерування ідентифікаторів з тією ж ентропією, що описана вище, але з використанням шістнадцяткових символів:
import EntropyString
let random = Random(.charSet16)
let bits = Entropy.bits(for: 5.0e6, risk: 1.0e12)
random.string(bits: bits)
"135fe71aec7a80c02dce5"
Зверніть увагу на різницю довжини рядка через різницю в загальній кількості символів у використаному наборі символів. Ризик повторення у вказаній кількості потенційних рядків однаковий. Довжина рядків не є. І найкраще, що ризик повторення та потенційна кількість рядків є явним. Більше не вгадуйте з довжиною рядка.
Якщо ваш випадковий рядок повинен бути захищеним-випадковим, скористайтеся цим:
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
}
Оновлено для 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
SWIFT 4
Використання RandomNumberGenerator для кращої продуктивності як рекомендація Apple
Використання: 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
}
}
Це Swift -est рішення , яке я міг придумати. 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
}
}
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
}