This question already has answers here:
How to check if a text field is empty or not in swift
(16 answers)
Checking if textfields are empty Swift
(6 answers)
Closed 4 years ago.
I'm currently working on a project where I use lots of UITextFields. For validation I need to check if the UITextFields are empty. I got a working solution, but it's not that elegant. Maybe someone knows a better way of doing it.
Here is my solution:
// Check if text field is empty
if let text = textField.text, !text.isEmpty {
// Text field is not empty
} else {
// Text field is empty
}
Is there a faster way without unwrapping the text attribute of the text field to find out if it's empty?
Thanks!
How about extending UITextField…
extension UITextField {
var isEmpty: Bool {
if let text = textField.text, !text.isEmpty {
return false
}
return true
}
}
so then…
if myTextField.isEmpty {
}
You can use UIKeyInput property hasText. It works for both UITextField and UITextView:
if textField.hasText {
// Text field is not empty
} else {
// Text field is empty
}
If you would like to check if the text has not only spaces on it:
extension UITextField {
var isEmpty: Bool {
return text?.trimmingCharacters(in: .whitespacesAndNewlines) == ""
}
}
let tf = UITextField()
tf.text = " \n \n "
tf.isEmpty // true
If you have several textfields that you want to check, you could put them all in a guard statement
guard let text1 = textField1.text, let text2 = textField2.text, let text3 = textField3.text, !text1.isEmpty, !text2.isEmpty, !text3.isEmpty else {
//error handling
return
}
//Do stuff
I like to validate each text field depending on the content that should be provided by the user, i.e. emailTextField should contain a valid email address etc. While Ashley Mills answer is convenient, if you regard whitespace " " as text this will return false.
In your case, since you need to validate multiple text fields in the same way, why not extend UITextField as Ashley did with a static class method that can validate each text field passed as an array, in addition to this have other validation methods for each type of text field. Instead of returning a Boolean value I've learned to use guard instead. In this way guard let can be used to check if the validation fails (is nil) and execute the proper code, such as displaying a prompt to the user, or otherwise continue execution.
UITextFieldExtension.swift
import Foundation
import UIKit
extension UITextField {
/// Validates all text field are non-nil and non-empty, Returns true if all fields pass.
/// - Returns: Bool
static func validateAll(textFields:[UITextField]) -> Bool {
// Check each field for nil and not empty.
for field in textFields {
// Remove space and new lines while unwrapping.
guard let fieldText = field.text?.trimmingCharacters(in: .whitespacesAndNewlines) else {
return false
}
// Are there no other charaters?
if (fieldText.isEmpty) {
return false
}
}
// All fields passed.
return true
}
//A function that validates the email address...
func validateEmail(field: UITextField) -> String? {
guard let trimmedText = field.text?.trimmingCharacters(in: .whitespacesAndNewlines) else {
return nil
}
//email addresses are automatically detected as links in i0S...
guard let dataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else {
return nil
}
let range = NSMakeRange(0, NSString(string: trimmedText).length)
let allMatches = dataDetector.matches(in: trimmedText,
options: [],
range: range)
if allMatches.count == 1,
allMatches.first?.url?.absoluteString.contains("mailto:") == true
{
return trimmedText
}
return nil
}
func validateUserName(field: UITextField) -> String? {
guard let text:String = field.text else {
return nil
}
/* 3 to 12 characters, no numbers or special characters */
let RegEx = "^[^\\d!##£$%^&*<>()/\\\\~\\[\\]\\{\\}\\?\\_\\.\\`\\'\\,\\:\\;|\"+=-]+$"
let Test = NSPredicate(format:"SELF MATCHES %#", RegEx)
let isValid = Test.evaluate(with: text)
if (isValid) {
return text
}
return nil
}
/*6 to 16 Characters */
func validatePassword(field: UITextField) -> String?{
guard let text:String = field.text else {
return nil
}
/*6-16 charaters, and at least one number*/
let RegEx = "^(?=.*\\d)(.+){6,16}$"
let Test = NSPredicate(format:"SELF MATCHES%#", RegEx)
let isValid = Test.evaluate(with: text)
if (isValid) {
return text
}
return nil
}
}
Meanwhile, elsewhere...
if (UITextField.validateAll(textFields: [emailTextField, nameTextField])) {
// Do something
}
Related
In ViewController - I have two text fields, like text field for text wihch user wants to reverse and text field for exclusions, and result-UILabel which shows the result.
In first text field user typing some text for reverse and result-UILabel shows the result of reversed text.
In the second text field, I want to make an exception for letters which shouldn't be reversed in result-UILabel. They should be untouchable in the word of the reverse at the time of reversing the text from the first field and should remain in their places.
The model function is in another swift file in another class.
Model function:
import Foundation
class ReverseWords {
public func reverse(textField: String) -> String {
if textField.isEmpty {
return ""
}
return textField.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: " ")
.map { String ( $0.reversed() ) }
.joined(separator: " ")
}
}
Using model function for first text field in ViewController:
resultLabel.text = reverseWords.reverse(textField:
reverseTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines))
Example:
First text field (for reverse) print:
FogmEistEr
Second text field (for exclusions) letters which should be untouchable of reverse, print:
E
And result label shows:
rtsiEmgoEF
How can I implement this?
How can I call exceptionTextField in model to check his characters inside?
Actually, I don't want to do this between classes, but I would like to look at the solution.
I think it would be better to do it in ViewController, but I got confused…
Have you any ideas, how to implement this?
I'd just make an extension on String:
extension String {
func reversed(omittingCharactersIn characterSet: CharacterSet) -> String {
var reversed = reversed()
.filter { String($0).rangeOfCharacter(from: characterSet) == nil }
let excluded = enumerated()
.filter { String($0.element).rangeOfCharacter(from: characterSet) != nil }
for (i, char) in excluded {
reversed.insert(char, at: reversed.index(reversed.startIndex, offsetBy: i))
}
return String(reversed)
}
}
All this is doing is reversing all of the characters right away, but removing any characters that should not be reversed. Then it finds and maintains the indices and characters should not move. Finally, it inserts the characters that should not be reversed back to their original position.
Usage:
let text = "FogmEistEr"
let omit = "E"
print(text.reversed(omittingCharactersIn: CharacterSet(charactersIn: omit)))
Prints:
rtsiEmgoEF
Here's how I'd plug it into a viewController assuming the reversal would happen either by a button push or by the text simply changing:
class ViewController: UIViewController {
#IBOutlet weak var originalTextField: UITextField!
#IBOutlet weak var exclusionTextField: UITextField!
#IBOutlet weak var reversedLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
originalTextField.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
exclusionTextField.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
}
#objc func textChanged(_ sender: UITextField) {
tryReverse()
}
#IBAction func didTapButton(_ sender: UIButton) {
tryReverse()
}
private func tryReverse() {
guard let originalText = originalTextField.trimmedTextNilIfEmpty,
let exclusionText = exclusionTextField.trimmedTextNilIfEmpty else {
reversedLabel.text = ""
return
}
reversedLabel.text = originalText.components(separatedBy: " ")
.map {
$0.reversed(omittingCharactersIn: CharacterSet(charactersIn: exclusionText))
}.joined(separator: " ")
}
}
extension UITextField {
var trimmedTextNilIfEmpty: String? {
if let trimmed = text?.trimmingCharacters(in: .whitespacesAndNewlines) {
return trimmed.isEmpty ? nil : trimmed
}
return nil
}
}
Here you can take reference for logic (It can be optimized). We can pass exclude reverse function. Rather than put this logic in the view controller I would suggest keeping the logic in ReverseWords class.
class ReverseWords {
public func reverse(textField: String, excludeWord: String) -> String {
if textField.isEmpty {
return ""
}
return textField.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: " ")
.map { $0 == excludeWord ? String($0) : reverseWordWithExclude(currentWord: String($0), excludeWord: excludeWord) }
.joined(separator: " ")
}
private func reverseWordWithExclude(currentWord: String, excludeWord: String) -> String {
// return direct reversed string if the exclude word not contain in string
if !currentWord.contains(excludeWord) {
return String(currentWord.reversed())
}
// Replace whole exception word with single space char which is never included in the current word.
// Easy to find the current index for a single space or for a char.
let replaceWord = currentWord.replacingOccurrences(of: excludeWord, with: " ")
var reverseString = ""
var exceptionIndexes: [Int] = []
// Find the index of exclude word and reverse string without include exclude word
replaceWord.enumerated().forEach { index, char in
if char == " " {
exceptionIndexes.append(index)
} else {
reverseString.insert((char), at: reverseString.startIndex)
}
}
// Now replace single space with actual exclude word at their position.
exceptionIndexes.forEach{ index in
reverseString.insert(contentsOf: excludeWord, at: reverseString.index(reverseString.startIndex, offsetBy: index))
}
return reverseString
}
}
I need to figure out a solution to prevent the app from crashing when a value is not entered in a textfield. The idea is if the textfield is empty (nil), the value of that textfield will then equal zero. Below I have copied my code:
let taxPercentDou:Double = Double(taxnosign2!)!
Anyone has any suggestions?
You need to stop force unwrapping optionals with the exclamation ! sign:
let b:Double = Double(rent.text!)!// Rent
If rent.text is nil or contains non-numeric text, your app will crash.
You can check for nil and replace it with "0" using the null coalescing operator:
rent.text ?? "0"
You can pass that into the Double initializer like this:
Double(rent.text ?? "0")
However, this will return nil if rent.text contains non-numeric text. You can use the null coalescing operator again to handle this:
let b: Double = Double(rent.text ?? "0") ?? 0.0
You could take this one step farther and write a simple utility method to make it easier to use for all your fields:
func convertToDouble(text: String?) -> Double {
return Double(text ?? "0") ?? 0.0
}
And call it like this:
let b = convertToDouble(rent.text)
Please find the below code. It Might Help you.
static func isNull(aString: AnyObject?) -> Bool
{
//Check for null
if(aString is NSNull){
return true
}
if(aString == nil){
return true
}
let x: AnyObject? = aString
//if string is nsnumber , convert it into string and check
if(aString is NSNumber){
var aString1 : String? = ""
aString1 = String(describing: aString)
return self.isStringEmpty(aString: aString1!)
}
if let aString1 = x as? String
{
return self.isStringEmpty(aString: aString1)
}
else
{
return true
}
}
I am working on textfields validations and getting confused how to validate textfield must contain at least 1 character from all of the following categories:
English uppercase characters (A - Z).
English lowercase characters (a - z).
Have a look at CharacterSets (described here)
You can create various Character sets (lowercase letters for instance) and test whether a string has content that matches said character set.
So, you could create a function which returns a boolean. The function checks your string against two CharacterSets and only if both can be found in the string, does the function return true.
Something like this
func validate(string: String) -> Bool {
let lowercase = CharacterSet.lowercaseLetters
let uppercase = CharacterSet.uppercaseLetters
let lowercaseRange = string.rangeOfCharacter(from: lowercase)
let uppercaseRange = string.rangeOfCharacter(from: uppercase)
return lowercaseRange != nil && uppercaseRange != nil
}
validate(string: "Hello") //returns true
validate(string: "hello") //returns false
validate(string: "HELLO") //returns false
Have a look at this article from NSHipster to learn more.
Credit : TextField uppercase and lowercase validation
Here is the regext for the condition :- Minimum 8 characters, 1 uppercase and 1 number.
^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[$#$!%?&])[A-Za-z\d$#$!%?&]{8,}
extension String {
func isValidPassword() -> Bool {
let regularExpression = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$#$!%*?&])[A-Za-z\\d$#$!%*?&]{8,}"
let passwordValidation = NSPredicate.init(format: "SELF MATCHES %#", regularExpression)
return passwordValidation.evaluate(with: self)
}
}
//Example 1
var password = "#Abcdef011" //string from UITextField (Password)
password.isValidPassword() // -> true
//Example 2
var password = "wer011" //string from UITextField
password.isValidPassword() // -> false
Simple extension accepts any CharacterSet to check:
extension String {
func hasCharacter(in characterSet: CharacterSet) -> Bool {
return rangeOfCharacter(from: characterSet) != nil
}
}
usage:
"aBc".hasCharacter(in: .lowercaseLetters)
"aBc".hasCharacter(in: .uppercaseLetters)
func isValidPassword(testStr:String?) -> Bool {
guard testStr != nil else { return false }
// at least one uppercase,
// at least one lowercase
// 8 characters total
let passwordTest = NSPredicate(format: "SELF MATCHES %#", "(?=.*[A-Z])(?=.*[a-z]).{8,}")
return passwordTest.evaluate(with: testStr)
}
in my app user can enter his email or phone number. I need to validate wether it's a phone number or email. if email entered it should be validated
ex: if user entered only "#mail.com" need to show not a valid mail to user.there should be at least 2 or three characters front of "#" here is my code
func validateEmail(enteredEmail:String) -> Bool {
let emailFormat = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format:"SELF MATCHES %#", emailFormat)
let email = emailPredicate.evaluate(with: enteredEmail)
if enteredEmail.contains("#") {
let characters = enteredEmail.components(separatedBy: "#")
if characters.count > 0 {
if characters[0].isEmpty {
return false
} else {
return true
}
}
}
return email ? email : enteredEmail.count == 10 //if email evaluation is false check for phone number count
}
This code is working fine for me but need a better solution. Thanks in advance
Why don't you simply modify the regex? It already checks if there is one or more characters before the # character. If you want to check for two or more use {2,}
let emailFormat = "[A-Z0-9a-z._%+-]{2,}#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
Apart from the phone validation this is a swiftier way to apply the regex
The pattern is
2 or more characters from the character set [A-Z0-9a-z._%+-]
one #
one or more characters from the character set [A-Za-z0-9.-]
one .
2-64 upper- or lowercase alpha letters
func validateEmail(enteredEmail:String) -> Bool {
let emailFormat = "[A-Z0-9a-z._%+-]{2,}#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
return enteredEmail.range(of: emailFormat, options: .regularExpression) != nil
}
If the entered string must exactly match the pattern use
let emailFormat = "^[A-Z0-9a-z._%+-]{2,}#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}$"
Edit:
To include also the phone validation (just 10 digits) use
func validateEmail(enteredEmail:String) -> Bool {
let emailFormat = "^[A-Z0-9a-z._%+-]{2,}#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}$"
guard enteredEmail.range(of: emailFormat, options: .regularExpression) == nil else { return true }
return enteredEmail.range(of: "^\\d{10}$", options: .regularExpression) != nil
}
use hasPrefix:
Example:
"hello dolly".hasPrefix("hello") // This will return true
"hello dolly".hasPrefix("abc") // This will return false
That way you can check if the first character is '#' or not and go on from there with an if-else statement.
Try This :
class func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: testStr)
}
the function is defined properly the issue that will be faced is when user type email like " #mail.com" as you are not trimming characters before validation.
Your code should be as follows:
if enteredEmail.contains("#")
{
let characters = enteredEmail.trimmingCharacters(in: CharacterSet.whitespaces).components(separatedBy: "#")
if characters.count > 0 {
if characters[0] > 2 {
return true
}else {
return false
}
}
}
The regex is fine: the error is in the return statement -and I actually don't like the code in the middle of the method-. You should validate phone numbers with another regex, not just string length, and then drop that if.
Here you have a cleaner example. You should change the phone number regex: it's for Spanish phone numbers.
import Foundation
func validateEmail(enteredEmail:String) -> Bool {
let emailFormat = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format:"SELF MATCHES %#", emailFormat)
let email = emailPredicate.evaluate(with: enteredEmail)
return email
}
func validatePhoneNumber(enteredPhoneNumber:String) -> Bool {
let phoneFormat = "\\A[0-9]{9}\\z"
let phonePredicate = NSPredicate(format:"SELF MATCHES %#", phoneFormat)
let phone = phonePredicate.evaluate(with: enteredPhoneNumber)
return phone
}
func validate(enteredString: String) -> Bool {
if validateEmail(enteredEmail: enteredString) == true {
return true
}
else {
return validatePhoneNumber(enteredPhoneNumber: enteredString)
}
}
validate(enteredString: "#email.com") // false
validate(enteredString: "some#email.com") // true: first regex
validate(enteredString: "666666666") // true: second regex
validate(enteredString: "some rubbish") // false
textField.text.isEmpty
textField.text != ""
These two functions regard spaces as characters. However, I would like my to recognise when the text field has no spaces or is not empty.
Just check if the trimmed string is empty
let isEmpty = str.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()).isEmpty
You can even put it in an String extension:
extension String {
var isReallyEmpty: Bool {
return self.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()).isEmpty
}
}
It even works for a string like var str = " " (that has spaces, tabs and zero-width spaces).
Then simply check textField.text?.isReallyEmpty ?? true.
If you wanna go even further (I wouldn't) add it to an UITextField extension:
extension UITextField {
var isReallyEmpty: Bool {
return text?.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()).isEmpty ?? true
}
}
Your code becomes textField.isReallyEmpty.
In Swift 4,
extension String {
var isReallyEmpty: Bool {
return self.trimmingCharacters(in: .whitespaces).isEmpty
}
}
I used this from #Pieter21 's link.
It works for as many blank spaces a user could enter.
let myString = TextField.text
let trimmedString = myString!.stringByTrimmingCharactersInSet(
NSCharacterSet.whitespaceAndNewlineCharacterSet()
)
if trimmedString != "" {
// Code if not empty
} else {
// Code if empty
}