iOS-键入时验证用户IP地址

时间:2018-09-03 13:26:45

标签: ios swift regex uitextfield uitextfielddelegate

所以我想在输入过程中验证用户ip。 在VC中,我执行以下操作:

extension NetworkSettingsViewController: UITextFieldDelegate {
  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    self.staticMask.resignFirstResponder()
    self.staticGateway.resignFirstResponder()
    self.staticIp.resignFirstResponder()
    self.staticDns.resignFirstResponder()
    return true
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    var isValidate: Bool
    //verify deletion not happening 
    if !(range.length == 1) {
        if validatorManager.verifyTarget(test: string) {

            isValidate = true
        } else {
            isValidate = false
        }
    } else {
        isValidate = true
    }
    return isValidate
}

}

这是验证类:

 class ValidatorManager: NSObject {

   func verifyTarget(test: String) -> Bool {
    //        let validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
    let validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.]){0,3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])?$"
    let ipTest = NSPredicate(format:"SELF MATCHES %@", validIpAddressRegex)
    print(ipTest.evaluate(with:test))
    return ipTest.evaluate(with:test)
  }
}

我已经尝试过2个正则表达式,但是什么也没有。 我想先检查一个字符,然后检查所有八位字节在dot()之前的所有3个字符。

4 个答案:

答案 0 :(得分:5)

这里有两个功能:第一个功能检查用户键入的内容是否有效(未完成的IP),第二个功能检查整个内容:

func verifyWhileTyping(test: String) -> Bool {
    let pattern_1 = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.]){0,3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])?$"
    let regexText_1 = NSPredicate(format: "SELF MATCHES %@", pattern_1)
    let result_1 = regexText_1.evaluate(with: test)
    return result_1
}

func verifyWholeIP(test: String) -> Bool {
    let pattern_2 = "(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})"
    let regexText_2 = NSPredicate(format: "SELF MATCHES %@", pattern_2)
    let result_2 = regexText_2.evaluate(with: test)
    return result_2
}

verifyWhileTyping(test:)中使用textField(_ textField: , shouldChangeCharactersIn range:, replacementString string:)在键入时进行检查。当用户完成操作并单击按钮或按下 Enter 键调用verifyWholeIP(test:)

//While typing
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if let text = textField.text {
        verifyWhileTyping(test: text + string)
    }
    //...
}

//When Enter is tapped
func textFieldShouldReturn(_ textField: UITextField) -> Bool {   
    textField.resignFirstResponder()
    if let text = textField.text {
        verifyWholeIP(test: text)
    }
    //...
    return true
}

pattern_1检查用户键入的内容是否是正确IP的开头:

regexText_1.evaluate(with: "0")        //true
regexText_1.evaluate(with: "255")      //true
regexText_1.evaluate(with: "256")      //false
regexText_1.evaluate(with: "10.10.")   //true
regexText_1.evaluate(with: "1.2..")    //false
regexText_1.evaluate(with: "1.2.3.4")  //true
regexText_1.evaluate(with: "1.2.3.4.") //false

对于pattern_2,它评估整个 IPv4

"(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})"

这里有更多测试用例:

regexText_2.evaluate(with: "0.0.0.0")    //true
regexText_2.evaluate(with: "1.1.1.256")  //false
regexText_2.evaluate(with: "-1.0.1.2")   //false
regexText_2.evaluate(with: "12.34.56")   //false
regexText_2.evaluate(with: "I.am.an.IP") //false

对于 IPv6 ,此正则表达式要使用:"[0-9A-Fa-f]{1,4}"中的pattern_2

答案 1 :(得分:3)

您可以使用正则表达式,也可以将IP地址字符串用点分隔,并检查每个部分是否为0到255范围内的整数:

func isValidIP(s: String) -> Bool {
    let parts = s.componentsSeparatedByString(".")
    let nums = parts.flatMap { Int($0) }
    return parts.count == 4 && nums.count == 4 && nums.filter { $0 >= 0 && $0 < 256}.count == 4
}

(假设您仅检查IPv4字符串。)

您也可以使用正则表达式很好地做到这一点。

import UIKit

infix operator =~ {}

func =~ (left: String, right: String) -> Bool {
    do {
        let regex = try NSRegularExpression(pattern: right, options: [])
        return regex.numberOfMatchesInString(left, options: [], range: NSMakeRange(0, (left as NSString).length)) > 0
    } catch {
        return false
    }
}

func isValidIP(s: String) -> Bool {
    let regex = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$"
    return s =~ regex
}

:问题在于它将匹配诸如“ 192.168.256.1”之类的字符串,该字符串不是有效的IP地址。用于仅检查有效IP的正则表达式实际上相当详细,而且很简单。

希望有帮助

答案 2 :(得分:1)

以下内容使您可以对从textField添加/删除的每个字符执行操作。您将不得不在方法内部调整操作。我目前在生产应用中使用此方法

textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControlEvents.editingChanged)

我还遇到了您遇到的问题,因为 shouldChangeCharactersIn 方法的字符太慢。在网上阅读了许多资料后,我得出结论,该方法实际上仅应用于简单的逻辑(仅我同意)

一旦添加了上面的代码行,就需要实现UITextFieldDelegate,如下所示:

//MARK: UITextFieldDelegate
func textFieldDidBeginEditing(_ textField: UITextField) {
    //Do something here
}

答案 3 :(得分:0)

一种非正则表达式替代方案,涵盖全部/部分验证,可以UITextFieldDelegate使用:

class InternetProtocolAddressValidation {

    enum Result { case fail, fullIP4, partialIP4 }

    class func validate(string: String) -> Result {

        let components = string.split(separator: ".")
        let validString = components.compactMap({ UInt8($0) }).map({ String($0) }).joined(separator: ".")

        if components.count == 4 && string == validString {
            return .fullIP4
        } else string.isEmpty || (1...3 ~= components.count && (string == validString || string == validString + ".")) {
            return .partialIP4
        } else {
            return .fail
        }
    }
}