So i want to validate the user ip during typing. In the VC i did the following :
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
}
}
This is the validation class :
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)
}
}
i have tried the 2 regex but nothing. i want to check char by char and then all the 3 before the dot() for all the octets.
Here are two functions: the first one checks what the user is typing is valid (unfinished IP), and the second one checks the whole thing:
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
}
Use verifyWhileTyping(test:)
in textField(_ textField: , shouldChangeCharactersIn range:, replacementString string:)
To check while typing. When the user is finished and clicks a button or hits the Enter key call 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
checks as the user is typing if it is the beginning of correct 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
As to pattern_2
, it evaluates a whole 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})"
Here are more test cases:
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
For IPv6 this the regex to use: "[0-9A-Fa-f]{1,4}"
in pattern_2
.
You can use a regex, You can also separate the IP address string by dots and check to see if each part is an integer in the range 0 to 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
}
(Assuming you're only checking IPv4 strings.)
You can also do it pretty nicely with a regex.
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
}
:The problem is that it will match strings like "192.168.256.1", which is not a valid IP address. The regex for checking only valid IPs is actually fairly detailed and non-trivial.
Hope it helps
The following allows you to perform an action with each character added/removed from your textField. You will have to adjust the action inside the method. I currently use this method in a production app
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
I also faced the issue you are having with the shouldChangeCharactersIn method being a character too slow. After reading many sources online I came to the conclusion this method should really only be used with simple logic (Just my opinion)
Once you've added the line of code above, you'll need to implement the UITextFieldDelegate as follows:
//MARK: UITextFieldDelegate
func textFieldDidBeginEditing(_ textField: UITextField) {
//Do something here
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With