Swift RegEx International - ios

I am checking for a valid birthday in a regEx after the user has entered their birthday in a date picker.
The issue is that if the phone is in Russian, Chinese, or any other language that uses other characters, the RegEx will not work due the month.
Is there an easy way to convert the month to digits (1-12) even though the month is displayed as letters and also work in any language?
If there was such a way, easy or not, it would be a lot easier to check if the user is exactly 13 years or older instead of just using the year.
func isValidBirthday(testStr4:String) -> Bool {
println("validate birthday: \(testStr4)")
let birthdayRegEx = "[A-Z0-9a-z, .]+(19[0-9][0-9]|200[0-3]|2003)"
let birthdayTest = NSPredicate(format: "SELF MATCHES %#", birthdayRegEx)
return birthdayTest.evaluateWithObject(testStr4)
}

I have a utilities class for checking Regex, using in a lot of my project
class Regex {
let internalExpression: NSRegularExpression!
let pattern: String
init(_ pattern: String) {
self.pattern = pattern
var error: NSError?
internalExpression = NSRegularExpression(pattern: pattern, options: .CaseInsensitive, error: &error)
}
func test(input: String) -> Bool {
if let matches = internalExpression?.matchesInString(input, options: nil, range:NSMakeRange(0, count(input))) {
return matches.count > 0
}
return false
}
}
For your case:
if Regex("^(19|20)\\d\\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$").test(DateStringValue) {
// Code to be executed in here
}
Hope it help.

Related

Use RegEx to validate a password on iOS Swift

I need to validate a user's password against the following requirements:
8 or more characters.
Contains 1 character and 1 number
Can enter letters, numbers, and symbols
Does anyone know how I can accomplish this using a RegEx?
I've made attempts to solve this problem on my own, but nothing I've tried so far as worked. The code for my latest attempt is below.
func isPasswordHasEightCharacter(password: String) -> Bool {
let passWordRegEx = "^.{8,}$"
let passwordTest = NSPredicate(format: "SELF MATCHES %#", passWordRegEx)
return passwordTest.evaluate(with: password)
}
func isPasswordHasNumberAndCharacter(password: String) -> Bool {
let passRegEx = "^(?=.*[a-z])(?=.*[0-9])"
let passwordTest = NSPredicate(format: "SELF MATCHES %#", passRegEx)
return passwordTest.evaluate(with: password)
}
func isPasswordHasNumberAndCharacterSign(password: String) -> Bool {
let passWordRegEx = "^(?!.[^a-zA-Z0-9##${'$'}^+=])"
let passwordTest = NSPredicate(format: "SELF MATCHES %#", passWordRegEx)
return passwordTest.evaluate(with: password)
}
In this solution each requirement is checked individually to avoid complex regular expressions. This solution supports variants of characters like ôöệż etc
func validatePassword(_ password: String) -> Bool {
//At least 8 characters
if password.count < 8 {
return false
}
//At least one digit
if password.range(of: #"\d+"#, options: .regularExpression) == nil {
return false
}
//At least one letter
if password.range(of: #"\p{Alphabetic}+"#, options: .regularExpression) == nil {
return false
}
//No whitespace charcters
if password.range(of: #"\s+"#, options: .regularExpression) != nil {
return false
}
return true
}
Some test cases
print(validatePassword("abc")) // --> false
print(validatePassword("abcdefgh")) // --> false
print(validatePassword("abcde fgh1")) // --> false
print(validatePassword("abcdefgh1")) // --> true
print(validatePassword("abcåäö123")) // --> true
print(validatePassword("ABC123€%&")) // --> true
print(validatePassword("#èệżôøö123")) // --> true
The main issue is that NSPredicate with MATCHES requires the full string to match and consume the whole input. Lookarounds - you are using lookaheads - do not consume text, that is, the texts they match are not added to the match value and the regex index stays where it was before attempting to match a lookaround pattern.
The last two parts can be thus fixed this way:
func isPasswordHasNumberAndCharacter(password: String) -> Bool {
let passRegEx = "(?=[^a-z]*[a-z])[^0-9]*[0-9].*"
let passwordTest = NSPredicate(format: "SELF MATCHES %#", passRegEx)
return passwordTest.evaluate(with: password)
}
func isPasswordHasNumberAndCharacterSign(password: String) -> Bool {
let passWordRegEx = "[a-zA-Z0-9!##$%^&*]+"
let passwordTest = NSPredicate(format: "SELF MATCHES %#", passWordRegEx)
return passwordTest.evaluate(with: password)
}
The first part is OK, though you do not need the ^ and $ anchors (as the whole string input must match the pattern). However, to check a string length you do not even need a regex: see Get the length of a String.
Note:
^(?=[^a-z]*[a-z])[^0-9]*[0-9].*\z matches a string that contains at least one lowercase ASCII letter and at least one ASCII digit
^[a-zA-Z0-9!##$%^&*]+$ will match a string that only contains ASCII letters, digits and some specific symbols. If you inlude a - make sure it is at the end. Escape both [ and ] if you need to add them, too.
If you want to combine all that into 1 regex you could use
let passRegEx = "(?=[^a-z]*[a-z])(?=[^0-9]*[0-9])[a-zA-Z0-9!##$%^&*]{8,}"
Or, if you are not using the regex with the NSPredicate MATCHES, with anchors:
let passRegEx = "\\A(?=[^a-z]*[a-z])(?=[^0-9]*[0-9])[a-zA-Z0-9!##$%^&*]{8,}\\z"

How to get full display name for locale

I want to show "繁體中文", "简体中文" in a view.
I use Locale.displayname to get displayname and my parameter is "zh-Hant" and "zh-Hans", the value will return "中文(繁體)"and "中文(简体)".
Here is parts of my code:
let loacleName = locale.displayName(forKey: NSLocale.Key.identifier, value: "zh-Hant")
Is anyone know how can I get "繁體中文", "简体中文" from iOS function?
This is a solution using native Locale. For the identifiers zh-Hant and zh-Hans it removes the unwanted characters with Regular Expression (be aware that the characters are not parentheses and space characters) and swaps both pairs.
extension Locale {
var localizedFullDisplayName : String? {
if self.identifier.hasPrefix("zh-Han") {
guard let trimmed = self.localizedString(forIdentifier: self.identifier)?.replacingOccurrences(of: "[()]", with: "", options: .regularExpression) else { return nil }
return String(trimmed.suffix(2) + trimmed.prefix(2))
} else {
return self.localizedString(forIdentifier: locale.identifier)
}
}
}
let locale = Locale(identifier: "zh-Hans")
locale.localizedFullDisplayName

backspace not work in outside of regex in swift

I use this method for patterning the phone number in UITextField at the .editingChange event
But the delete key only removes the numbers
extension String{
func applyPatternOnNumbers(pattern: String) -> String {
let replacmentCharacter: Character = "#"
let pureNumber = self.replacingOccurrences( of: "[^۰-۹0-9]", with: "", options: .regularExpression)
var result = ""
var pureNumberIndex = pureNumber.startIndex
for patternCharacter in pattern {
if patternCharacter == replacmentCharacter {
guard pureNumberIndex < pureNumber.endIndex else { return result }
result.append(pureNumber[pureNumberIndex])
pureNumber.formIndex(after: &pureNumberIndex)
} else {
result.append(patternCharacter)
}
}
return result
}
}
use at the editingChange event
let pattern = "+# (###) ###-####"
let mobile = textField.text.substring(to: pattern.count-1)
textfield.text = mobile.applyPatternOnNumbers(pattern: pattern)
// print(textfield.text) +1 (800) 666-8888
the problem is space & - , ( , ) chars can not to be removed
The RegEx you are trying is to not consider digits only:
[^۰-۹0-9]
I'm not sure, but you may change it to:
[^۰-۹0-9\s-\(\)]
and it may work. You might just add a \ before your special chars inside [] and you can any other chars into it that you do not need to be replaced.
Or you may simplify it to
[^\d\s-\(\)]
and it might work.
Method 2
You may use this RegEx which is an exact match to the phone number format you are having:
\+\d+\s\(\d{3}\)\s\d{3}-\d{4}
You may remove the first +, if it is unnecessary
\d+\s\(\d{3}\)\s\d{3}-\d{4}

Swift: how to censor/filter text entered for swear words, etc?

I just want to see whether there is an established way to do this, or how one would go about this.
I have a text field that essentially acts as a form in my iOs app where a user can post something. I can't have users posting swear words/inappropriate crap, so I want to filter out and display an error if the string they enter contains one of these words.
How do other apps in Swift do this? Do they just search through the string to see if it contains the word (obviously not within other words, but standing alone) or is there another method?
How can I accurately filter out the swear words from my user post in Swift?
Construct a list of words you consider to be swear words, and simply check the user entered string whether any of these words are contained within the string.
Swift 3:
import Foundation
func containsSwearWord(text: String, swearWords: [String]) -> Bool {
return swearWords
.reduce(false) { $0 || text.contains($1.lowercased()) }
}
// example usage
let listOfSwearWords = ["darn", "crap", "newb"]
/* list as lower case */
let userEnteredText1 = "This darn didelo thread is a no no."
let userEnteredText2 = "This fine didelo thread is a go."
print(containsSwearWord(text: userEnteredText1, swearWords: listOfSwearWords)) // true
print(containsSwearWord(text: userEnteredText2, swearWords: listOfSwearWords)) // false
Swift 2.2:
import Foundation
func containsSwearWord(text: String, swearWords: [String]) -> Bool {
return swearWords
.reduce(false) { $0 || text.containsString($1.lowercaseString) }
}
// example usage
let listOfSwearWords = ["darn", "crap", "newb"]
/* list as lower case */
let userEnteredText1 = "This darn didelo thread is a no no."
let userEnteredText2 = "This fine didelo thread is a go."
print(containsSwearWord(userEnteredText1, swearWords: listOfSwearWords)) // true
print(containsSwearWord(userEnteredText2, swearWords: listOfSwearWords)) // false
I created a class that enables you to feed a string in and remove profanity. Here's a link to the repo.
Here's the code:
class ProfanityFilter: NSObject {
static let sharedInstance = ProfanityFilter()
private override init() {}
// Customize as needed
private let dirtyWords = "\\b(ducker|mother ducker|motherducker|shot|bad word|another bad word|)\\b"
// Courtesy of Martin R
// https://stackoverflow.com/users/1187415/martin-r
private func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [.caseInsensitive])
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
public func cleanUp(_ string: String) -> String {
let dirtyWords = matches(for: self.dirtyWords, in: string)
if dirtyWords.count == 0 {
return string
} else {
var newString = string
dirtyWords.forEach({ dirtyWord in
let newWord = String(repeating: "😲", count: dirtyWord.characters.count)
newString = newString.replacingOccurrences(of: dirtyWord, with: newWord, options: [.caseInsensitive])
})
return newString
}
}
}
Usage:
yourLabel.text = ProfanityFilter.sharedInstance.cleanUp(yourString)
Extension checking for foul language.
Swift 4.2
Example Usage:
"poop".containsBadWord()
Extension:
extension String {
func containsBadWord()->Bool {
//Sorry for bad words
let badWords = ["insert","bad","words","here","poop"]
for word in badWords {
if lowercased().contains(word) {
return true
}
}
return false
}
}
I would suggest looking into an API to which you can submit a string and get a JSON response containing information such as:
Is the string bad?
Total # of bad words contained in string
An array containing all recognized bad words
A censored version of the input string
I found a couple sources via Google. Check these out and do a little more research to find if an API is the best fit for you and which one you should use. I would assume that using an API like the one I have listed below would be the most practical approach, as you would NOT have to compile a list of "bad" words yourself and use resources from the device to sort through the list (which can contain thousands of words).
Rather, you can simply submit a string using the API to get a network response containing the data in JSON format from the API server.
Why not let the API Server do the logic for you and just spit out an answer?
NeutrinoAPI
If this method returns a range,
str.range(of: "darn|crap|newb", options: [.regularExpressionSearch, .caseInsensitiveSearch], range: str.startIndex..<str.endIndex, locale:nil)
an offensive word has been found. While this method can be used to remove the offending strings:
str.replacingOccurrences(of: "darn|crap|newb", with: "", options: [.regularExpressionSearch, .caseInsensitiveSearch])
If you filter bad words locally you wouldn’t easily accommodate many languages, also as new bad words appear, you would have to waste a developers time manually putting in bad words, alternatively, there are apis designed for this purpose: https://www.moderatecontent.com/documentation/badwords

Check if string is 3 chars and 3 number in Swift

I'm trying to create a function that validate my string if it is using this format
ABC123
First three characters should be letters and the other 3 should be numbers
I have no idea on how to start
Thanks
You can do it with a regular expression match on strings, like this:
let str = "ABC123"
let optRange = str.rangeOfString("^[A-Za-z]{3}\\d{3}$", options: .RegularExpressionSearch)
if let range = optRange {
println("Matched")
} else {
println("Not matched")
}
Regex above requires that the match occupied the whole string (the ^ and $ anchors at both ends), has three letters [A-Za-z]{3} and three digits \\d{3}.
You can also use it as an extension if you would like to:
extension String {
var match: Bool {
return rangeOfString("^[A-Za-z]{3}\\d{3}$", options: .RegularExpressionSearch) != nil
}
}
"ABC123".match // true

Resources