在andom索引处插入字符串不能正常工作

时间:2015-07-04 15:07:14

标签: ios arrays swift numbers generator

我正在研究一个随机密码生成器,我希望有一个用户可以输入的基本字符串,并在基本字符串内部或周围生成随机字符。我的问题是,只要它用基本字符串生成随机字符,它们就会插入前面(第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)
    }
}

任何帮助将不胜感激。谢谢!

3 个答案:

答案 0 :(得分:5)

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

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

构建哪些构建块只能通过练习来实现,但是如果您发现自己重复使用相同的相同代码并且一次又一次地重复相同的代码,那么就像您在各种{{ {1}}函数 - 这些是以有用的方式分解代码的示例。

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

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

(以下所有内容均为Swift 2.0代码,但除非您计划在不到3个月的时间内将产品投放到生产中,特别是如果您正在学习Swift,我强烈建议升级,因为它是 比1.2更容易使用,你最终必须升级,离开的时间越长就越痛苦。

arc4random

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

/// 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 : [])
    }
}

然后,当您构建这个随机密码生成函数时,您应该从视图控制器中调用它。但是你不必 - 你可以单独调用它,这使得测试和检查它的工作和调试变得容易得多。独立功能也可以独立测试。

答案 1 :(得分:1)

您的代码存在很多问题(正如评论已经告诉您的那样)。我的一些功能正在运行,即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()

其中一个示例输出是 B 我的 D T 0Q <强>分机 X

让我解释一下您的代码无法正常工作的几点:

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

答案 2 :(得分:0)

根据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
  密码:0uniG39i⃝3cHNod4e