Reputation: 2963
How can I generate a random alphanumeric string in Swift?
Upvotes: 290
Views: 148865
Reputation: 52227
You can use randomSample(count:)
from the Swift Algorithm package. Add it to your project via "File > Add package Dependencies..." in "Apple Swift Packages"
import Algorithms
extension String {
static func shuffled(length:Int = 1024, alphabet:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String {
String(alphabet.randomSample(count: length))
}
}
usage:
print(String.shuffled(length:6))
print(String.shuffled())
print(String.shuffled(length: 3, alphabet: "abcdefg"))
results:
FwHk5B
xNjKGiV3QhnPBFbZv5epUYC2zmgOD61kWR0qwsTcaHMt7lLAJu49XEyrd8ISfo
gdc
Documentation for randomSample(count k: Int) -> [Element]
/// Randomly selects the specified number of elements from this collection.
///
/// This method is equivalent to calling `randomSample(k:using:)`, passing in
/// the system's default random generator.
///
/// - Parameter k: The number of elements to randomly select.
/// - Returns: An array of `k` random elements. The returned elements may be
/// in any order. If `k` is greater than this collection's count, then this
/// method returns the full collection.
///
/// - Complexity: O(*k*), where *k* is the number of elements to select, if
/// the collection conforms to `RandomAccessCollection`. Otherwise, O(*n*),
/// where *n* is the length of the collection.
Upvotes: 1
Reputation: 12385
The simplest way would be to define the character set and construct a string using random elements from that set.
Below is an example of a password generator using printable ASCII characters. For extensibility and efficiency, I've defined the character set as a static property on String
. The function then takes an integer argument for password length and returns a random string.
extension String {
static let printableASCII: Set<Character> = [
" ", "!", "\"", "#", "$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".",
"/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=",
">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
"M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[",
"\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
"k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
"z", "{", "|", "}", "~"
]
}
func getStrongPassword(ofLength count: Int) -> String {
var password = String()
for _ in 0..<count {
password.append(String.printableASCII.randomElement()!)
}
return password
}
print(getStrongPassword(ofLength: 18)) // \g'CeTBRcLguQJ_(*S
Note, that printableASCII
contains 3 escaped characters in the Swift language, which are backslash, double quotation mark, and single quotation mark.
Upvotes: -1
Reputation: 52227
String.shuffeld(length:)
shuffles the alphabet. the returned String will not contain duplicates. if alphabet is shorter than length the returned String will have the length of alphabet.
String.random(length:)
will return a String that may contain duplicates and is guaranteed to be of size length.
extension String {
static func shuffeld(length: Int, alphabet:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String? {
guard
alphabet.count > 0
&& length > 0
else { return nil }
return alphabet.shuffled().prefix(length).map {String($0)}.joined()
}
}
extension String {
static func random(length: Int, alphabet:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String? {
let a = (0..<length).reduce("") { partialResult, _ in
partialResult + alphabet
}
return shuffeld(length: length, alphabet: a)
}
}
Usage:
print(String.shuffeld(length: 15)!)
print(String.shuffeld(length: 3, alphabet: "abcdefg")!)
print(String.random(length: 100)!)
print(String.random(length: 10, alphabet: "🙂☹️")!)
example output:
y37Ji8cLsPIQutr
dcf
UPfErOiryiuApH3HKHaZl6guY3LwXkmBqyyxqQAIw39lBK2R8mrwtbYKRhL80mZwkV2sf24No9PPXg6uwmUwVljbcUwSVeFBCUdD
☹️☹️🙂🙂☹️☹️🙂🙂☹️🙂
Upvotes: 0
Reputation: 23
This is the Swift-est solution I could come up with. 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("") { accum, _ in
let randomOffset = arc4random_uniform(randomLength)
let randomIndex = letters.index(letters.startIndex, offsetBy: Int(randomOffset))
return accum.appending(String(letters[randomIndex]))
}
return randomString
}
}
Upvotes: -2
Reputation: 12648
Here is an extremely clear function that caches. You should certainly cache as a matter of good practice. (There's also FWIW a tiny performance advantage to caching, which is of course totally irrelevant in an app.)
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)
}
This is for when you have a fixed, known character set.
Handy tip:
There is no 0, o, O, i, etc ... the characters humans often confuse.
This is often done for booking codes and similar codes which human customers will use.
Upvotes: 16
Reputation: 977
Swift 5.6
This function generates a number which is 10 digits in base 36, then returns it as an alphanumeric string.
func randomCode(length: Int) -> String {
let radix = 36 // = 10 digits + 26 letters
let max = Int(pow(Double(radix), Double(length)))
let number = Int.random(in: 0..<max)
return String(number, radix: radix, uppercase: true)
}
Or if you never want the code to start with "0":
func randomCode(length: Int) -> String {
let radix = 36 // = 10 digits + 26 letters
let max = Int(pow(Double(radix), Double(length)))
let min = max / 2
let number = Int.random(in: min..<max)
return String(number, radix: radix, uppercase: true)
}
Upvotes: 1
Reputation: 3075
A way that avoids typing out the entire set of characters:
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)
}
Upvotes: 9
Reputation: 21468
Here's a ready-to-use solution in Swiftier syntax. You can simply copy and paste it:
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
}
If you prefer a Framework that also has some more handy features then feel free to checkout my project HandySwift. It also includes a beautiful solution for random alphanumeric strings:
String(randomWithLength: 8, allowedCharactersType: .alphaNumeric) // => "2TgM5sUG"
Upvotes: 64
Reputation: 692
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)
Upvotes: 15
Reputation: 6704
Swift 4.2 Update
Swift 4.2 introduced major improvements in dealing with random values and elements. You can read more about those improvements here. Here is the method reduced to a few lines:
func randomString(length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..<length).map{ _ in letters.randomElement()! })
}
Swift 3.0 Update
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
}
Original answer:
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
}
Upvotes: 497
Reputation: 2238
SWIFT 4
Using RandomNumberGenerator for better performance as Apple recommendation
Usage: String.random(20)
Result: 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
}
}
Upvotes: 2
Reputation: 38667
A pure Swift random String
from any CharacterSet
.
Usage: 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
}
}
The characters()
function is my fastest known implementation.
Upvotes: 6
Reputation: 36630
Loop free, though it is limited to 43 characters. If you need more, it can be modified. This approach has two advantages over solely using a UUID:
UUID()
only generates upper case lettersUUID
is at most 36 characters long (including the 4 hyphens), but only 32 characters long without. Should you need something longer, or not want hyphens included, the use of the base64EncodedString
handles thisAlso, this function makes use of a UInt
to avoid negative numbers.
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))
}
Calling it in a loop to check output:
for _ in 0...10 {
print(generateRandom(size: 32))
}
Which produces:
Nzk3NjgzMTdBQ0FBNDFCNzk2MDRENzZF
MUI5RURDQzE1RTdCNDA3RDg2MTI4QkQx
M0I3MjJBRjVFRTYyNDFCNkI5OUM1RUVC
RDA1RDZGQ0IzQjI1NDdGREI3NDgxM0Mx
NjcyNUQyOThCNzhCNEVFQTk1RTQ3NTIy
MDkwRTQ0RjFENUFGNEFDOTgyQTUxODI0
RDU2OTNBOUJGMDE4NDhEODlCNEQ1NjZG
RjM2MTUxRjM4RkY3NDU2OUFDOTI0Nzkz
QzUwOTE1N0U1RDVENDE4OEE5NTM2Rjcy
Nzk4QkMxNUJEMjYwNDJDQjhBQkY5QkY5
ODhFNjU0MDVEMUI2NEI5QUIyNjNCNkVF
Upvotes: 7
Reputation: 188
Updated for Swift 4. Use a lazy stored variable on the class extension. This only gets computed once.
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
Upvotes: 1
Reputation: 2350
With Swift 4.2 your best bet is to create a string with the characters you want and then use randomElement to pick each character:
let length = 32
let characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomCharacters = (0..<length).map{_ in characters.randomElement()!}
let randomString = String(randomCharacters)
I detail more about these changes here.
Upvotes: 12
Reputation: 2357
If your random string should be secure-random, use this:
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
}
Upvotes: 3
Reputation: 61814
You may use it also in the following way:
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
}
}
Simple usage:
let randomString = String.random()
Swift 3 Syntax:
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 Syntax:
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
}
}
Upvotes: 53
Reputation: 5821
Simple and Fast -- UUID().uuidString
// Returns a string created from the UUID, such as "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
Please don't confuse with UIDevice.current.identifierForVendor?.uuidString
it won't give random values.
Upvotes: 18
Reputation: 1445
The problem with responses to "I need random strings" questions (in whatever language) is practically every solution uses a flawed primary specification of string length. The questions themselves rarely reveal why the random strings are needed, but I would challenge you rarely need random strings of length, say 8. What you invariably need is some number of unique strings, for example, to use as identifiers for some purpose.
There are two leading ways to get strictly unique strings: deterministically (which is not random) and store/compare (which is onerous). What do we do? We give up the ghost. We go with probabilistic uniqueness instead. That is, we accept that there is some (however small) risk that our strings won't be unique. This is where understanding collision probability and entropy are helpful.
So I'll rephrase the invariable need as needing some number of strings with a small risk of repeat. As a concrete example, let's say you want to generate a potential of 5 million IDs. You don't want to store and compare each new string, and you want them to be random, so you accept some risk of repeat. As example, let's say a risk of less than 1 in a trillion chance of repeat. So what length of string do you need? Well, that question is underspecified as it depends on the characters used. But more importantly, it's misguided. What you need is a specification of the entropy of the strings, not their length. Entropy can be directly related to the probability of a repeat in some number of strings. String length can't.
And this is where a library like EntropyString can help. To generate random IDs that have less than 1 in a trillion chance of repeat in 5 million strings using EntropyString
:
import EntropyString
let random = Random()
let bits = Entropy.bits(for: 5.0e6, risk: 1.0e12)
random.string(bits: bits)
"Rrrj6pN4d6GBrFLH4"
EntropyString
uses a character set with 32 characters by default. There are other predefined characters sets, and you can specify your own characters as well. For example, generating IDs with the same entropy as above but using hex characters:
import EntropyString
let random = Random(.charSet16)
let bits = Entropy.bits(for: 5.0e6, risk: 1.0e12)
random.string(bits: bits)
"135fe71aec7a80c02dce5"
Note the difference in string length due to the difference in total number of characters in the character set used. The risk of repeat in the specified number of potential strings is the same. The string lengths are not. And best of all, the risk of repeat and the potential number of strings is explicit. No more guessing with string length.
Upvotes: 3
Reputation: 3022
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
}
Upvotes: -3
Reputation: 2296
If you just need a unique identifier, UUID().uuidString
may serve your purposes.
Upvotes: 0
Reputation: 12214
for 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
}
Upvotes: 5
Reputation: 265
Swift 2.2 Version
// 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
}
Basically call this method that will generate a random string the length of the integer handed to the function. To change the possible characters just edit the charactersString string. Supports unicode characters too.
https://gist.github.com/gingofthesouth/54bea667b28a815b2fe33a4da986e327
Upvotes: 6
Reputation: 6703
My even more Swift-ier implementation of the question:
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("")
}
Upvotes: 3
Reputation: 5158
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
}
Upvotes: 2