ORKTextAnswerFormat regex validation - ios

I am trying to incorporate a custom ORKTextAnswerFormat into my app, and only allow users to enter alphanumeric characters. I only want upper/lowercase letters and numbers - no symbols or accented letters.
E.G. they should not be allowed to enter "example!", as it includes an exclamation mark.
The code I have tried so far is as follows:
// REGEX
let linkRegexPattern = "[^a-zA-Z0-9]"
let linkRegex = try! NSRegularExpression(pattern: linkRegexPattern,
options: .caseInsensitive)
// CUSTOM STEP TO INPUT PATIENT ID
let patientidTitle = "Patient ID"
let patientidQuestion = "Enter the Patient ID provided to you by the hospital."
let patientidAnswerFormat = ORKTextAnswerFormat(validationRegularExpression: linkRegex, invalidMessage: "INVALID")
patientidAnswerFormat.maximumLength = 20
patientidAnswerFormat.multipleLines = false
let patientidStep = ORKQuestionStep(identifier: "patientIDstep", title: patientidTitle, question: patientidQuestion, answer: patientidAnswerFormat)
patientidStep.isOptional = false
However upon entering the above example, I am able to press next and move on to the next question/step with no errors thrown. I would like it to not allow me to proceed until the input is suitable.
How can I achieve this?
EDIT:
If I input "test" it alerts saying it is invalid. However, inputting "test!" allows me to continue.

The [^a-zA-Z0-9] pattern finds a char other than a digit or letter in the input string and returns a match then.
You need a regex that matches an entire string made of letters or digits. Thus, you may use
let linkRegexPattern = "^[a-zA-Z0-9]*\\z"
It matches
^ - start of string
[a-zA-Z0-9]* - 0+ letters or digits
\z - the very end of the string.

Related

Regex to not allow staring whitespace in string swift ios

I want to create regex thats allows characters numbers and spaces but not at the begning of string , i have created below one but its not working "^\\S.*[^A-Za-z0-9_ ].*".
Swift:
func containsAllowedCharacters(regex: String?, stringToCheck: String) -> Bool {
var isValid = false
if let regex = regex {
let testString = NSPredicate(format: "SELF MATCHES %#", regex)
isValid = testString.evaluate(with: stringToCheck)
}
return !isValid
}
Your pattern, ^\S.*[^A-Za-z0-9_ ].*, matches start of string with ^, then matches any non-whitespace char with \S (note it matches any punctuation, letters and digits), then matches any zero or more chars other than line break chars as many as possbile with .*, then matches any char other than an ASCII letter, digit, _ or space, and then again matches any zero or more chars other than line break chars as many as possbile with .*.
As you see, all the pattern parts match more than you allow. Also, pay attention you actually require at least two chars to be present with this pattern while your code implies you need to support zero length string, too.
You can use
let FileNameRegex = #"^(?!\s)[A-Za-z0-9_\s]*$"#
NOTE: As you are using it with MATCHES in the NSPredicate.evaluate, you do not need the ^ and $ anchors on both ends since MATCHES requires a full string match:
let FileNameRegex = #"(?!\s)[A-Za-z0-9_\s]*"#
let testString = NSPredicate(format: "SELF MATCHES %#", regex)
Note the use of #"..."# notation that makes a raw string literal, where a single backslash is parsed as a literal backslash.
The pattern matches
^ - start of string
(?!\s) - a negative lookahead that matches a location in string that is not immediately followed with a whitespace
[A-Za-z0-9_\s]* - zero or more (due to the * quantifier) ASCII letters, digits, underscores and whitespaces
$ - end of string.
You are looking for lookaheads:
^(?! )[ \w]+$
\w is a short form for [\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\u200c\u200d] (see here and here for more information) as it is used very often, but see #Wiktor's comment for a more precise clarification.
Also,see a demo on regex101.com.

Can I use iOS9 Contacts Framework to get a formatted phone number?

I would like to be able to store a phone number in a standard way, e.g. just the digits (potentially with the '+' for the country code), something like these examples...
"17185555555"
"+17185555555"
"+447788888888"
... but I'd like to be able to DISPLAY it to a user in a properly formatted way, e.g.
"1 (718) 555-5555"
"+1 (718) 555-5555"
"+44 (7788) 888888"
...WITHOUT having to rely on a CNContactViewController to format it.
Obviously doing this just for US/Canada numbers would be easy - it's just one standard format - but I'd like it to be generic so it can work for numbers from any country. I know this question gives an answer for US/Can numbers only.
I know that I could use a CNContactViewController to display the number in the correct format, e.g.
let newContact = CNMutableContact()
newContact.givenName = "John"
newContact.familyName = "Smith"
newContact.phoneNumbers = [CNLabeledValue(label: CNLabelPhoneNumberiPhone, value: CNPhoneNumber(stringValue:"17185555555"))]
let contactView = CNContactViewController(forContact: newContact)
self.presentViewController(contactView, animated: true, completion: nil)
This will show the number on screen properly formatted, i.e.
1 (718) 555-5555
... so I know that something in the framework can do it. (This approach works for other country phone number formats, as long as you prefix the number with the right country code - e.g. "+44...")
From various other questions I know that I can get the raw digits and country code out of a CNContact, e.g. (following above example)
for pNumber: CNLabeledValue in newContact.phoneNumbers {
let value = pNumber.value as! CNPhoneNumber
let cc = value.valueForKey("countryCode") as? String
let digits = value.valueForKey("digits") as? String
print("cc:" + cc + ", " + digits)
}
... but this will just show the unformatted string again - not what I am looking for in this case.
Any help or other recommended approaches really appreciated!
My answer proposes another lib
You can format your numbers with this lib.
And you can use like this:
let phoneNumber: NBPhoneNumber = try phoneUtil.parse("17185555555", defaultRegion: yourRegion)
let formattedString: String = try phoneUtil.format(phoneNumber, numberFormat: .E164)

swift ios alpha numeric regex that allows underscores and dashes

I am using this lib for validation and are trying to add my own regex.
What I want to do is to make a regex that allows alphanumeric A-Z 0-9 together with dashes and unserscores -_
I have tryed let regex = "[a-zA-Z0-9_-]" but I cant get it to work.
I also want the regex to not only allow english letters, but all languishes.
The lib works cause I have made another regex that only allows ints 0-9 which works
let intRegex = "^[0-9]*$"
Your regex look good but it will only match a single character. Do this "^[a-zA-Z0-9_-]*$" instead to match more than one character.
breakup --
^ -- start of string
[\pL0-9_-] -- characters you want to allow
* -- any number of characters (the crucial bit you were missing)
$ -- end of string
Building up on #charsi's answer
extension String {
var isAlphanumericDashUnderscore: Bool {
get {
let regex = try! NSRegularExpression(pattern: "^[a-zA-Z0-9_-]*$", options: .caseInsensitive)
return regex.firstMatch(in: self, options: [], range: NSRange(location: 0, length: count)) != nil
}
}
}

How to avoid an error due to special characters in search string when using Regex for a simple search in Swift?

I'm using Regex to search for a word in a textView. I implemented a textField and two switch as options (Whole words and Match case). All work fine when you enter a plain word in the search filed but I get an error when I enter a special character like \ or *.
The error I get is like this one:
Error Domain=NSCocoaErrorDomain Code=2048 "The value “*” is invalid." UserInfo={NSInvalidValue=*}
Is there a way to avoid this problem and have the code handle all the text like plain text?
Because I would like to search also for special characters, I would like to prefer to not interdict to enter them. At the beginning I though to programmatically add an escape backslash to all special character before to perform a search, but maybe there are some more smart approaches?
Here is the code I'm using (based on this tutorial: NSRegularExpression Tutorial: Getting Started)
struct SearchOptions {
let searchString: String
var replacementString: String
let matchCase: Bool
let wholeWords: Bool
}
extension NSRegularExpression {
convenience init?(options: SearchOptions) {
let searchString = options.searchString
let isCaseSensitive = options.matchCase
let isWholeWords = options.wholeWords
// handle case sensitive option
var regexOption: NSRegularExpressionOptions = .CaseInsensitive
if isCaseSensitive { // if it is match case remove case sensitive option
regexOption = []
}
// put the search string in the pattern
var pattern = searchString
// if it's whole word put the string between word boundary \b
if isWholeWords {
pattern = "\\b\(searchString)\\b" // the second \ is used as escape
}
do {
try self.init(pattern: pattern, options: regexOption)
} catch {
print(error)
}
}
}
You may use NSRegularExpression.escapedPatternForString:
Returns a string by adding backslash escapes as necessary to protect any characters that would match as pattern metacharacters.
Thus, you need
var pattern = NSRegularExpression.escapedPatternForString(searchString)
Also, note that this piece:
if isWholeWords {
pattern = "\\b\(searchString)\\b"
might fail if a user inputs (text) and wishes to search for it as a whole word. The best way to match whole words is by means of lookarounds disallowing word chars on both ends of the search word:
if isWholeWords {
pattern = "(?<!\\w)" + NSRegularExpression.escapedPatternForString(searchString) + "(?!\\w)"

How to capitalize each word in a string using Swift iOS

Is there a function to capitalize each word in a string or is this a manual process?
For e.g. "bob is tall"
And I would like "Bob Is Tall"
Surely there is something and none of the Swift IOS answers I have found seemed to cover this.
Are you looking for capitalizedString
Discussion
A string with the first character in each word changed to its corresponding uppercase value, and all remaining characters set to their corresponding lowercase values.
and/or capitalizedStringWithLocale(_:)
Returns a capitalized representation of the receiver using the specified locale.
For strings presented to users, pass the current locale ([NSLocale currentLocale]). To use the system locale, pass nil.
Swift 3:
var lowercased = "hello there"
var stringCapitalized = lowercased.capitalized
//prints: "Hello There"
Since iOS 9 a localised capitalization function is available as capitalised letters may differ in languages.
if #available(iOS 9.0, *) {
"istanbul".localizedCapitalizedString
// In Turkish: "İstanbul"
}
An example of the answer provided above.
var sentenceToCap = "this is a sentence."
println(sentenceToCap.capitalizedStringWithLocale(NSLocale.currentLocale()) )
End result is a string "This Is A Sentence"
For Swift 3 it has been changed to capitalized .
Discussion
This property performs the canonical (non-localized) mapping. It is suitable for programming operations that require stable results not depending on the current locale.
A capitalized string is a string with the first character in each word changed to its corresponding uppercase value, and all remaining characters set to their corresponding lowercase values. A “word” is any sequence of characters delimited by spaces, tabs, or line terminators (listed under getLineStart(_:end:contentsEnd:for:)). Some common word delimiting punctuation isn’t considered, so this property may not generally produce the desired results for multiword strings.
Case transformations aren’t guaranteed to be symmetrical or to produce strings of the same lengths as the originals. See lowercased for an example.
There is a built in function for that
nameOfString.capitalizedString
This will capitalize every word of string. To capitalize only the first letter you can use:
nameOfString.replaceRange(nameOfString.startIndex...nameOfString.startIndex, with: String(nameOfString[nameOfString.startIndex]).capitalizedString)
Older Thread
Here is what I came up with that seems to work but I am open to anything that is better.
func firstCharacterUpperCase(sentenceToCap:String) -> String {
//break it into an array by delimiting the sentence using a space
var breakupSentence = sentenceToCap.componentsSeparatedByString(" ")
var newSentence = ""
//Loop the array and concatinate the capitalized word into a variable.
for wordInSentence in breakupSentence {
newSentence = "\(newSentence) \(wordInSentence.capitalizedString)"
}
// send it back up.
return newSentence
}
or if I want to use this as an extension of the string class.
extension String {
var capitalizeEachWord:String {
//break it into an array by delimiting the sentence using a space
var breakupSentence = self.componentsSeparatedByString(" ")
var newSentence = ""
//Loop the array and concatinate the capitalized word into a variable.
for wordInSentence in breakupSentence {
newSentence = "\(newSentence) \(wordInSentence.capitalizedString)"
}
// send it back up.
return newSentence
}
}
Again, anything better is welcome.
Swift 5 version of Christopher Wade's answer
let str = "my string"
let result = str.capitalized(with: NSLocale.current)
print(result) // prints My String

Resources