在 andom 索引处插入字符串无效 swift

Insert string at andom index is not working swift

我正在开发一个随机密码生成器,我想要一个用户可以输入的基本字符串,并在基本字符串内部或周围生成随机字符。我的问题是,每当它使用基本字符串生成随机字符时,它们就会被插入到前面(第 0 个索引)。这是我的代码:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var baseStringTextField: UITextField!
    @IBOutlet weak var lowerCaseSwitch: UISwitch!
    @IBOutlet weak var upperCaseSwitch: UISwitch!
    @IBOutlet weak var numberSwitch: UISwitch!
    @IBOutlet weak var numberOfCharactersSlider: UISlider!
    @IBOutlet weak var numberOfCharsLabel: UILabel!

    let lower = ["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"]
    let upper = ["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"]
    let numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    let lowerUpper = ["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",]

    let lowerNumber = ["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","1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    let upperNumber = ["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","1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    let all = ["a", "A" ,"b", "B", "c", "C", "d", "D", "e", "E" , "f", "F", "g", "G",  "h", "H", "i", "I",  "j", "J" ,"k", "K", "l", "L" ,"m", "M" , "n", "N" ,"o", "O", "p", "P",  "q", "Q", "r", "R", "s", "S", "t", "T", "u", "U", "v", "V", "w", "W", "x","X", "y", "Y" , "z", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    var generatedString = [""]


    func generateLower(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var char = lower[Int(arc4random_uniform(26))]
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateUpper(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var char = upper[Int(arc4random_uniform(26))]
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateNumber(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var char = numbers[Int(arc4random_uniform(10))]
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateLowerAndUpper(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
                var char = lowerUpper[Int(arc4random_uniform(52))]
                baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateLowerAndNumber(){
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        srandom(UInt32(time(nil)))
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
                var char = lowerNumber[Int(arc4random_uniform(36))]
                baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateUpperAndNumber(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
                var char = upperNumber[Int(arc4random_uniform(36))]
                baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateAll(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            println(count_)
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_)))
            var char = all[Int(arc4random_uniform(62))]
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    @IBAction func generateString(sender: UIButton) {
        if(lowerCaseSwitch.on && upperCaseSwitch.on && numberSwitch.on){
            generateAll()
        }else if(lowerCaseSwitch.on && upperCaseSwitch.on == false && numberSwitch.on == false){
            generateLower()
        }else if(upperCaseSwitch.on && lowerCaseSwitch.on == false && numberSwitch.on == false){
            generateUpper()
        }else if(numberSwitch.on && lowerCaseSwitch.on == false  && upperCaseSwitch.on == false){
            generateNumber()
        }else if(lowerCaseSwitch.on && upperCaseSwitch.on && numberSwitch.on == false){
            generateLowerAndUpper()
        }else if(lowerCaseSwitch.on && numberSwitch.on && upperCaseSwitch.on == false){
            generateLowerAndNumber()
        }else if(upperCaseSwitch.on && numberSwitch.on && lowerCaseSwitch.on == false){
            generateUpperAndNumber()
        }
    }

    @IBAction func copyButtonPressed(sender: UIButton) {
        UIPasteboard.generalPasteboard().string = "".join(generatedString)
}
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        view.endEditing(true)
        super.touchesBegan(touches, withEvent: event)
    }
}

如有任何帮助,我们将不胜感激。谢谢!

您的代码将非常难以调试,因为它混合了许多不同的东西——从数组中获取随机元素、从随机元素构建字符串、更新 UI、从 UI 获取设置以控制代码。

如果您养成将需要做的事情分解为多个构建块的习惯,您会发现在第一次尝试时编写正确的代码并让自己摆脱调试地狱要容易得多。

要构建哪些构建基块只能通过练习来实现,但是如果您发现自己一遍又一遍地重复相同的代码,但有细微的变化,那么您遇到问题的一个好兆头,就像您在自己的工作中所做的那样各种 generateXXX 函数 – 这些是以 没有 有用的方式分解代码的示例。

例如,您需要一个函数来生成给定长度的密码,可以选择包含各种字符。为此,您需要一个从数组(或任何集合)中获取随机字符的函数。为此,您需要一个将系统生成的随机数转换为集合索引的函数。这些可能会成为很好的积木。

所以,一个转换 arc4random_uniform 的函数(顺便说一句,不需要调用 srandarc4random 种子本身):

(以下均为 Swift 2.0 代码,但除非您计划在不到 3 个月内将某些东西投入生产,尤其是如果您正在学习 Swift,我' d 强烈建议升级,因为它比 1.2 更容易使用,而且你最终必须升级,离开它的时间越长会越痛苦)

/// Version of arc4random that works for any integer type. Kinda ugly unfortunately.
func arc4random_uniform<In: _SignedIntegerType, Out: _SignedIntegerType>(upto: In) -> Out 
{
    precondition(upto < numericCast(UInt32.max),"Range too big for arc4random")
    return numericCast(Darwin.arc4random_uniform(numericCast(upto.toIntMax())))
}

然后是一个从集合中获取随机元素的函数。这通常适用于任何集合类型,但您可以只为数组编写它,因为如果这就是您所需要的,那么这样做会更容易:

/// Fetch a random element from any collection that supports random access
extension CollectionType where Index: RandomAccessIndexType {
    var randomElement: Generator.Element {
        guard !isEmpty else { fatalError("Collection cannot be empty") }
        return self[startIndex.advancedBy(arc4random_uniform(count))]
    }
}

然后,为您可能想要包含的不同类型的字符设置一个选项:

/// A set of options for controlling which characters to include in a password
struct CharacterOptions: OptionSetType {
    let rawValue: Int
    init(rawValue: Int) { self.rawValue = rawValue }

    static let LowerCase = CharacterOptions(rawValue: 1)
    static let UpperCase = CharacterOptions(rawValue: 2)
    static let Numbers = CharacterOptions(rawValue: 4)

    /// An array of the full set of characters based on the options set
    var characters: [Character] {
        let lower = Array("abcdefghijklmnop".characters)
        let upper = Array("ABCDEFGHIKKLMNOP".characters)
        let numbers = Array("1234567890".characters)

        // this could be done so much more efficiently if only
        // LazyRandomAccessCollection supported flatMap
        return (self.contains(.LowerCase) ? lower   : [])
             + (self.contains(.UpperCase) ? upper   : [])
             + (self.contains(.Numbers)   ? numbers : [])
    }
}

最后将它们组合成一个生成密码的函数:

func generatePassword(length: Int, options: CharacterOptions) -> String {
    let sources: [Character] = options.characters

    let characters = (0..<length).map { _ in
        sources.randomElement
    }

    return String(characters)
}

generatePassword(10, options: [.LowerCase, .UpperCase])

然后,当你构建了这个随机密码生成函数后,你应该从你的视图控制器中调用它。但您不必这样做——您可以单独调用它,这样可以更轻松地测试和检查它是否正常工作以及调试。单机功能也可以独立测试

您的代码有很多问题(评论已经告诉您)。我得到了你的函数的一个版本,即 generateUpperAndNumber。以下代码的开头只是为了函数能够对有效数据进行操作 - 你关心的是 generateUpperAndNumber:

的新实现
var baseStringTextField = UITextField()
baseStringTextField.text = "myText"

var numberOfCharactersSlider = UISlider()
numberOfCharactersSlider.minimumValue = 1
numberOfCharactersSlider.maximumValue = 20
numberOfCharactersSlider.value = 13

let upperNumber:[Character] = ["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","1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

var generatedString:[Character] = []
var generatedStringLabel = UILabel()

func generateUpperAndNumber() {
    var baseString = Array(baseStringTextField.text!.characters)
    for var i = 0; i < Int(numberOfCharactersSlider.value) ; ++i {
        let count_ = baseString.count

        let randIndex = Int(arc4random_uniform(UInt32(count_ + 1)))
        let char = upperNumber[Int(arc4random_uniform(UInt32(upperNumber.count)))]

        baseString.insert(char, atIndex: randIndex)
    }

    generatedString = baseString
    var genString = ""
    for c in baseString {
        genString += String(c)
    }
    generatedStringLabel.text = genString
}

generateUpperAndNumber()

一个示例输出是 BmyDT 0QextX

让我解释一下您的代码没有按预期工作的几点:

  • Array(arrayLiteral: baseStringTextField.text) returns 一个数组,其中只有文本作为其中的单个元素。你想要一个包含所有字符的数组 -> Array(baseStringTextField.text!.characters)
  • 你的 randIndex 根本没有任何意义。它应该只选择一个介于 0 和当前数组大小之间的索引
  • 您有大量代码重复 - 只有您插入的字符不同 -> 将您要选择的字符作为 generateX()
  • 的参数传递
  • 与其使用从 某处 神奇地获取相关输入的方法,不如将 textField 的字符串作为参数传入。

这是我根据 luk2302 和 Airspeed Velocity (Swift 2.0)

之前的回答得出的结论
func insertionCharacters(lowerCase lowerCase: Bool, upperCase: Bool, numbers: Bool) -> String {
    var characters :String = ""
    if lowerCase {
        characters += "abcdefghijklmnop"
    }
    if upperCase {
        characters += "ABCDEFGHIKKLMNOP"
    }
    if numbers {
        characters += "1234567890"
    }
    return characters
}

func generatePasscode(length: Int, baseString: String, insertCharacters: String) -> String {
    let insertCharacterList = Array(insertCharacters.characters)
    let insertCharacterCount :UInt32 = UInt32(insertCharacterList.count)
    guard insertCharacterCount>0 else { return baseString}

    var baseArray = Array(baseString.characters)
    for _ in 0..<length {
        let count_ = baseArray.count

        let randIndex = Int(arc4random_uniform(UInt32(count_ + 1)))
        let insertCharacterIndex = Int(arc4random_uniform(insertCharacterCount))
        let insertCharacter = insertCharacterList[insertCharacterIndex]

        baseArray.insert(insertCharacter, atIndex: randIndex)
    }

    var genString = ""
    for c in baseArray {
        genString += String(c)
    }

    return genString
}

用法示例:

func generate() {
    let baseString = baseStringTextField.text
    let insertCount = numberOfCharactersSlider.value

    let characters = insertionCharacters(lowercase:lowerCaseSwitch.on, upperCase:upperCaseSwitch.on, numbers:numberSwitch.on)
    let passcode = generatePasscode(insertCount, baseString:baseString, insertCharacters: characters)

    let baseStringTextField.text = passcode
}
generate()

测试:

func test() {
    let insertCount = 8
    let baseString = "unii⃝code"

    print("baseString: \(baseString)")
    let characters = insertionCharacters(lowerCase:false, upperCase:true, numbers:true)
    let passcode = generatePasscode(insertCount, baseString:baseString, insertCharacters: characters)
    print("passcode: \(passcode)")
}
test()

测试输出:

baseString: unii⃝code
passcode: 0uniG39i⃝3cHNod4e