Swiftでランダムな英数字の文字列を生成する


208

Swiftでランダムな英数字の文字列を生成するにはどうすればよいですか?

回答:


355

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

4
randomString(length:6)またはrandomString(length:8)
Simon H

58

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
}

さらに便利な機能を備えたフレームワークを好む場合は、私のプロジェクトHandySwiftを自由にチェックアウトしてください。また、ランダムな英数字の文字列の美しいソリューションも含まれています

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

49

次の方法でも使用できます。

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

29

迅速:

let randomString = NSUUID().uuidString

UUID()。uuidStringが現在
Mark Bridgesが

2
UUIDは時々同じ文字列を与えます!
BurakÖztürk、

2
UUIDにはさまざまな種類があり、一部は時間ベースです。Swift Foundationで使用されているものは、ランダムなV4です。可能性はほとんどありません(たとえば、同じUUIDが2回生成されることは信じられないほど少ないです。)
Robin Daugherty

11

スウィフト4.2あなたの最善の策は、あなたがしたい文字の文字列を作成し、使用することですrandomElementを各文字を選択します:

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

これらの変更の詳細については、こちらをご覧ください


3
マップの代わりに、compactMapを使用できます。その場合、その必要はありません。オペレーター。;)
Kristaps Grinbergs 2018

1
@KristapsGrinbergsさん、こんにちは!強制アンラップは、compactMapを使用するよりもパフォーマンスが良いと私は考えました。
レオディオン2018

11

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:ます。
・クール

10

シンプルかつ高速な - 。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ランダムな値を与えないことと混同ないでください


6

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


2
いくつかの不幸な理由で、このバージョンは時折与えますEXC_BAD_INSTRUCTION
ジョー

ジョーさん、このエラーを再現できるデモコードはありますか?
アーネストカニンガム2016年

何ができるか見てみましょう。私はそれをそのままIBアクションアウトレットでそのまま呼び出していましたlet random = randomString(16)。EXCは実際のデバイスにのみ存在し、シミュレーターには表示されず、デバイスで断続的でした。
ジョー

1
:これは32ビットのデバイス上半分の時間をクラッシュした理由のために、このSOの質問を参照してくださいstackoverflow.com/questions/25274265/...
julien_c

重要:( 常に)均一な分布を作成random % countしませ。これがあなたに関連している場合は、を使用する他の回答を探してくださいarc4random_uniform()
Raphael

6

文字セット全体を入力したくない人のために:

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

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
そのコードを試しましたか?返される文字列の長さが間違っていて、数字しかないことに気づきましたか?同じ問題があるstackoverflow.com/q/39566062/1187415を見てください。
マーティンR

@MartinR指摘してくれてありがとう。私は私の答えを更新しました
S1LENT WARRIOR 2016

5

String任意のからの純粋なSwiftランダム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()関数である私の最速知ら実装


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

私の質問のより迅速な実装:

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

ループフリーですが、43文字に制限されています。さらに必要な場合は、変更できます。このアプローチには、UUIDを単独で使用するよりも2つの利点があります。

  1. 大文字UUID()のみを生成するため、小文字を使用したエントロピーの増加
  2. Aの長さUUIDは最大36文字(4つのハイフンを含む)ですが、32文字しかありません。より長いものが必要な場合、またはハイフンを含めたくない場合は、base64EncodedStringこのハンドルを使用すると

また、この関数はa 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

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

「ランダムな文字列が必要です」という質問(どんな言語でも)に対する応答の問題は、事実上すべてのソリューションが文字列長の欠陥のある主要な仕様を使用していることです。質問自体は、ランダム文字列が必要な理由をめったに明らかにしませんが、長さ8のランダム文字列が必要になることはめったにありません。たとえば、何らかの目的で識別子として使用するために、いくつかの一意の文字列が常に必要です。

厳密に一意の文字列を取得するは、主に2つの方法があります。確定的(ランダムではない)と保存/比較(煩わしい)です。私たちは何をしますか?私たちは幽霊をあきらめます。代わりに、確率的な一意性を使用します。つまり、文字列が一意でなくなるリスクが(わずかではありますが)あることを受け入れます。これは、衝突確率エントロピーを理解することが役立つ場所です。

したがって、繰り返しのリスクが少ない、いくつかの文字列が必要になるので、不変のニーズを言い換えます。具体的な例として、500万のIDを生成したいとします。新しい文字列を保存して比較するのではなく、文字列をランダムにしたいので、繰り返しのリスクを受け入れます。例として、1兆回の繰り返しで1未満のリスクがあるとします。では、どのくらいの長さのストリングが必要ですか?まあ、それは使用される文字に依存するので、その質問は十分に指定されていません。しかし、より重要なことに、それは見当違いです。必要なのは、文字列の長さではなく、文字列のエントロピーの仕様です。エントロピーは、いくつかの文字列で繰り返しが発生する確率に直接関係しています。文字列の長さはできません。

そして、これがEntropyStringのようなライブラリが役立つところです。を使用して500万の文字列で1兆回の繰り返しの可能性が1未満のランダムIDを生成するには、次のようにしますEntropyString

import EntropyString

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

「Rrrj6pN4d6GBrFLH4」

EntropyStringデフォルトでは32文字の文字セットを使用します。他にも事前定義された文字セットがあり、独自の文字を指定することもできます。たとえば、上記と同じエントロピーで16進数文字を使用してIDを生成します。

import EntropyString

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

「135fe71aec7a80c02dce5」

使用する文字セットの合計文字数の違いによる文字列の長さの違いに注意してください。指定された数の潜在的な文字列で繰り返されるリスクは同じです。文字列の長さは異なります。そして何よりも、繰り返しのリスクと文字列の潜在的な数は明白です。文字列の長さを推測する必要はもうありません。


2

ランダムな文字列を安全なランダムにする必要がある場合は、次のようにします。

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

一意の識別子だけが必要なUUID().uuidString場合は、目的に役立つことがあります。


1

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

1

SWIFT 4

Appleの推奨事項としてRandomNumberGeneratorを使用してパフォーマンスを向上させる

使用法: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
    }
}

0

これは私が思いつくことができる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
    } 
}

-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
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.