10

Working on a Swift app and I have a form filled by user and I would like the user to select their own username. The only constraints I want on the username are:

  • No special characters (e.g. @,#,$,%,&,*,(,),^,<,>,!,±)
  • Only letters, underscores and numbers allowed
  • Length should be 18 characters max and 7 characters minimum

Where can I find a function that validates an input string (function parameter) and return true or false based on above criteria? I am not very well versed in regular expressions.

1
  • 3
    You should post what you tried. Commented Jun 21, 2016 at 7:50

5 Answers 5

25

You may use

^\w{7,18}$ 

or

\A\w{7,18}\z 

See the regex demo

Pattern details:

  • ^ - start of the string (can be replaced with \A to ensure start of string only matches)
  • \w{7,18} - 7 to 18 word characters (i.e. any Unicode letters, digits or underscores, if you only allow ASCII letters and digits, use [a-zA-Z0-9] or [a-zA-Z0-9_] instead)
  • $ - end of string (for validation, I'd rather use \z instead to ensure end of string only matches).

Swift code

Note that if you use it with NSPredicate and MATCHES, you do not need the start/end of string anchors, as the match will be anchored by default:

func isValidInput(Input:String) -> Bool { let RegEx = "\\w{7,18}" let Test = NSPredicate(format:"SELF MATCHES %@", RegEx) return Test.evaluateWithObject(Input) } 

Else, you should not omit the anchors:

func isValidInput(Input:String) -> Bool { return Input.range(of: "\\A\\w{7,18}\\z", options: .regularExpression) != nil } 
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you for your support...The explanation is really helpful...allows me to modify for future scenarios
why is it necessary to specify start of the string and end of the string?
@andrei You do not have to use \A and \z in case you are using the regex with MATCHES in the NSPredicate as it anchors the regex pattern by default. However, it is a good idea to keep the anchors explicit in the pattern in case you want to test it in any online regex testers, or just to have a better feel of what the regex does. Also, if you use it in other methods that do not anchor the pattern by default, its behavior won't change.
so if I understand correctly, it is necessary when trying a regex with an online tool, as it matches regexes only between the anchors. I might have a longer string, but regex matching will only apply to the part of it that's between the anchors. Is that correct?
@andrei I suggest you read Anchors at rexegg.com. ^ or \A will match the start of the string, and $ or \z will match the end of the string, and if you place anything before ^ or after $, the pattern will never match as there are no chars before the start of the string and there are no chars after its end.
8
func validateUsername(str: String) -> Bool { do { let regex = try NSRegularExpression(pattern: "^[0-9a-zA-Z\\_]{7,18}$", options: .CaseInsensitive) if regex.matchesInString(str, options: [], range: NSMakeRange(0, str.characters.count)).count > 0 {return true} } catch {} return false } 

1 Comment

Found this easier to edit and use for name validation too. Thanks mate
3

In Swift 4

extension String { var isValidName: Bool { let RegEx = "^\\w{7,18}$" let Test = NSPredicate(format:"SELF MATCHES %@", RegEx) return Test.evaluate(with: self) } } 

Comments

0
func isValidUsername(testStr:String) -> Bool { var rawString: String = testStr var whitespace: NSCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet() trimmed = rawString.stringByTrimmingCharactersInSet(whitespace) if trimmed.characters.count>0 { return true } else { return false } } 

Comments

0

Regular expressions are powerful, but here is pure Swift solution. Exact answer to your question:

func isValidUsername(_ name: String, forbiddenChars: String = "@#$%&*()^<>!±", lengthRange: Range<Int> = 3..<19) -> Bool { guard lengthRange ~= name.count , name.first!.isLetter else { return false } return name.allSatisfy{ !forbiddenChars.contains($0) } } isValidUsername("tom3") // true isValidUsername("tom_c") // false (note disallowed underscope) isValidUsername("3tom") // false isValidUsername("tom#$%&") // false 

A common thing to want is to have only alphanumerics in a user name:

func alphanumericsOnly(_ name: String, lengthRange: Range<Int> = 3..<19) -> Bool { guard lengthRange ~= name.count , name.first!.isLetter else { return false } return name.allSatisfy{ $0.isLetter || $0.isNumber } } 

Important thing to note here is that some emoji's and all diacritics count as alphanumerics which may be not what you want.

alphanumericsOnly("tom3️⃣") // true alphanumericsOnly("Ḡ͓̟̟r̬e̱̬͔͑g̰ͮ̃͛T̆a̐̑͢ṫ̀ǔ̓͟m̮̩̠̟") // true alphanumericsOnly("tom_") // false 

So the most strict way for latin username can be checked as follows:

func asciiOnly<R: RangeExpression>(_ name: String, lengthRange: R) -> Bool where R.Bound == Int { guard lengthRange ~= name.count , name.first!.isLetter else { return false } return name.allSatisfy{ $0.isASCII } } asciiOnly("tom_c", lengthRange: 3...) // true (infinite length) asciiOnly("tom3️⃣", lengthRange: 3...18) // false asciiOnly("tomё", lengthRange: 3..<19) // false 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.