user9874788
user9874788

Reputation:

How to check whether String only consists of letters and spaces in Swift 5?

I am currently trying to validate a name input field. For that purpose I would like to check the input.

The input is a string and should only consist of letters and spaces. Is there any simple way to implement it.

For example I have the Input of "Jon Doe", how can I verify that this a acceptable name while Peter2or Ben&Jerryisnt?

Thanks for your help in advance. <3

Upvotes: 2

Views: 2741

Answers (4)

DonMag
DonMag

Reputation: 77486

Depending on the exact requirements, RegEx may be the better route.

  • Are leading / trailing / extra spaces valid?
  • Are extended Latin characters valid?
  • Are punctuated names valid (hyphenated or apostrophes)?

For example, with this list of "name" entries:

    "Jon Doe",
    "Ben&Jerry",
    "JonDoe",
    "Jon Edward Doe",
    " Jon Doe",
    "Jon   Doe",
    "Jon Doe ",
    "Jon Doe2",
    "José Doe",
    "Jon O'Doe",
    "Jon Doe-Smith",
    "Joß Müller",
    "Jon 黒澤明"

Which ones should be valid?

EDIT: updated with better (?) RegEx based on Rob's answer...

Using this code, which evaluates the entries with both .rangeOfCharacter and with a RegEx test:

class ViewController: UIViewController {

    override func viewDidLoad() {

        let names: [String] = [
            "Jon Doe",
            "Ben&Jerry",
            "JonDoe",
            "Jon Edward Doe",
            " Jon Doe",
            "Jon   Doe",
            "Jon Doe ",
            "Jon Doe2",
            "José Doe",
            "Jon O'Doe",
            "Jon Doe-Smith",
            "Joß Müller",
            "Jon 黒澤明",
        ]

        names.forEach {
            test($0)
        }

    }

func test(_ text: String) -> Void {

        let ss = "^[\\p{L}\\p{P}]+\\s[\\p{L}\\p{P}]+$"

        let b1 = text.range(of: ss, options: .regularExpression) != nil

        let lettersAndSpacesCharacterSet = CharacterSet.letters.union(.whitespaces).inverted

        let b2 = text.rangeOfCharacter(from: lettersAndSpacesCharacterSet) == nil

        print("RegEx:", b1, "\t", "Range:", b2, "\t", "[\(text)]")

    }

}

The output is:

RegEx: true      Range: true     [Jon Doe]
RegEx: false     Range: false    [Ben&Jerry]
RegEx: false     Range: true     [JonDoe]
RegEx: false     Range: true     [Jon Edward Doe]
RegEx: false     Range: true     [ Jon Doe]
RegEx: false     Range: true     [Jon   Doe]
RegEx: false     Range: true     [Jon Doe ]
RegEx: false     Range: false    [Jon Doe2]
RegEx: true      Range: true     [José Doe]
RegEx: true      Range: false    [Jon O'Doe]
RegEx: true      Range: false    [Jon Doe-Smith]
RegEx: true      Range: true     [Joß Müller]
RegEx: true      Range: true     [Jon 黒澤明]

Upvotes: 0

Rob
Rob

Reputation: 437622

You have to decide how permissive you want to be. There are common Western exceptions including:

  • double-barreled names (“Daniel Day-Lewis”);
  • accents (“José Mourinho”);
  • apostrophes (“Chris O’Dowd”);
  • abbreviations for lineage (“Martin Luther King Jr.”), titles (“Dr. Li Wenliang”), and credentials (“John Nash, Ph.D.”)

Plus, if you eventually localized the app for other languages, you might want

  • non-Western character sets (“黒澤明”)

Regex handles this stuff gracefully, e.g. this is for any letter and a few select punctuation symbols:

let searchString = #"^([\p{L},.'’-]+(\s|$))+"#

if string.range(of: searchString, options: .regularExpression) != nil {
    print(string, "passed")
} else {
    print(string, "failed")
}

If you don’t want to permit the periods or commas, feel free to remove them from the above regex.

Upvotes: 0

Alejandro L.Rocha
Alejandro L.Rocha

Reputation: 1145

you could also do something like this

func onlyLettersChecker(string: String) -> Bool {

    let justLettersRegex = "[^A-Za-zÀ-ÖØ-öø-ÿ]"

    let trimmedString = string.replacingOccurrences(of: " ", with: "")
    return trimmedString.isEmpty == false && trimmedString.range(of: justLettersRegex, options: .regularExpression) == nil
}

You delete the whitespaces of your string, and then check if there are only letters there.

That regex accepts accents in the names, you might need to modify the regex if you need some apostrophes in your names and so on.

Upvotes: 1

Goergisn
Goergisn

Reputation: 647

let lettersAndSpacesCharacterSet = CharacterSet.letters.union(.whitespaces).inverted

let testValid1 = "Jon Doe".rangeOfCharacter(from: lettersAndSpacesCharacterSet) == nil // true
let testInvalid1 = "Ben&Jerry".rangeOfCharacter(from: lettersAndSpacesCharacterSet) == nil // false
let testInvalid2 = "Peter2".rangeOfCharacter(from: lettersAndSpacesCharacterSet) == nil // false

Upvotes: 13

Related Questions