Check whether an NSString contains a special character and a digit - objective-c

I need to check whether a string contains one uppercase letter, one lower case letter, one integer and one special character. How do I check?

Without any additional frameworks:
NSCharacterSet * set = [[NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"] invertedSet];
if ([aString rangeOfCharacterFromSet:set].location != NSNotFound) {
NSLog(#"This string contains illegal characters.");
}
You could also use a regex (this syntax is from RegexKitLite: http://regexkit.sourceforge.net):
if ([aString isMatchedByRegex:#"[^a-zA-Z0-9]"]) {
NSLog(#"This string contains illegal characters.");
}

Found a slightly better implementation. Improvement on Ameesh's answer
- (BOOL)isValidString:(NSString *)string
{
return [string rangeOfCharacterFromSet:[NSCharacterSet uppercaseLetterCharacterSet]].location != NSNotFound &&
[string rangeOfCharacterFromSet:[NSCharacterSet lowercaseLetterCharacterSet]].location != NSNotFound &&
[string rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location != NSNotFound;
}

Maulik's answer is incorrect. That will check for anything OTHER than any alphanumeric character, but doesn't enforce that there be one uppercase letter, one lowercase letter, and one integer. You do in fact have to do 3 checks to verify each constraint.
NSCharacterSet *lowerCaseChars = [NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyz"];
NSCharacterSet *upperCaseChars = [NSCharacterSet characterSetWithCharactersInString:#"ABCDEFGHIJKLKMNOPQRSTUVWXYZ"];
NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
if ([aString rangeOfCharacterFromSet:lowerCaseChars].location == NSNotFound || [aString rangeOfCharacterFromSet:upperCaseChars].location = NSNotFound || [aString rangeOfCharacterFromSet:numbers].location == NSNotFound) {
NSLog(#"This string contains illegal characters");
}

For Arabic/English
NSString *regEx = #"^([a-zA-Z0-9\u0600-\u06ff](\\-|\\_|\\.|\\ )?)+$";
NSPredicate *regExPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",regEx];
BOOL myStringMatchesRegEx = [regExPredicate evaluateWithObject: self.text];
if (!myStringMatchesRegEx)
return NO;

Here is what I would do. Create Regular expressions for every condition you need to check if corresponding value present or not.
i.e. Regular Expression to check if it has one uppercase letter, one lower case letter , one integer and one special character, and so on.
and then use the same string to check against every regular expression if all of them return true you have winner if not then string doesn't match to your criteria.
// Example for the Validating UpperCaseLetter do same for all others with matching regular expression.
-(BOOL) validateOneUpperCaseLetter:(NSString *)string {
if ((string == nil) || ([string isEqualToString: #""])) {
return NO;
}
// Change this regEx to one you needed. // this one validates for the "name".
NSString *regEx = #"^[a-zA-Z]+(([\\'\\,\\.\\ -][a-zA-Z])?[a-zA-Z]\\s*)*$";
NSPredicate *regExPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",regEx];
BOOL myStringMatchesRegEx = [regExPredicate evaluateWithObject: string];
if (!myStringMatchesRegEx) {
return NO;
}
return YES;}

Related

Check if NSString only contains one character repeated

I want to know a simple and fast way to determine if all characters in an NSString are the same.
For example:
NSString *string = "aaaaaaaaa"
=> return YES
NSString *string = "aaaaaaabb"
=> return NO
I know that I can achieve it by using a loop but my NSString is long so I prefer a shorter and simpler way.
you can use this, replace first character with null and check lenght:
-(BOOL)sameCharsInString:(NSString *)str{
if ([str length] == 0 ) return NO;
return [[str stringByReplacingOccurrencesOfString:[str substringToIndex:1] withString:#""] length] == 0 ? YES : NO;
}
Here are two possibilities that fail as quickly as possible and don't (explicitly) create copies of the original string, which should be advantageous since you said the string was large.
First, use NSScanner to repeatedly try to read the first character in the string. If the loop ends before the scanner has reached the end of the string, there are other characters present.
NSScanner * scanner = [NSScanner scannerWithString:s];
NSString * firstChar = [s substringWithRange:[s rangeOfComposedCharacterSequenceAtIndex:0]];
while( [scanner scanString:firstChar intoString:NULL] ) continue;
BOOL stringContainsOnlyOneCharacter = [scanner isAtEnd];
Regex is also a good tool for this problem, since "a character followed by any number of repetitions of that character" is in very simply expressed with a single back reference:
// Match one of any character at the start of the string,
// followed by any number of repetitions of that same character
// until the end of the string.
NSString * patt = #"^(.)\\1*$";
NSRegularExpression * regEx =
[NSRegularExpression regularExpressionWithPattern:patt
options:0
error:NULL];
NSArray * matches = [regEx matchesInString:s
options:0
range:(NSRange){0, [s length]}];
BOOL stringContainsOnlyOneCharacter = ([matches count] == 1);
Both these options correctly deal with multi-byte and composed characters; the regex version also does not require an explicit check for the empty string.
use this loop:
NSString *firstChar = [str substringWithRange:NSMakeRange(0, 1)];
for (int i = 1; i < [str length]; i++) {
NSString *ch = [str substringWithRange:NSMakeRange(i, 1)];
if(![ch isEqualToString:firstChar])
{
return NO;
}
}
return YES;

validate alphanumeric value in UITextField

I want alphanumeric value in textfield.If user enter only character or number then sending massage.Even no special characters acceptable.
NSString *str = askIdTxt.text;
NSCharacterSet *alphanumericSet = [NSCharacterSet alphanumericCharacterSet];
NSCharacterSet *numberSet = [NSCharacterSet decimalDigitCharacterSet];
BOOL isAlphaNumericOnly = [[str stringByTrimmingCharactersInSet:alphanumericSet] isEqualToString:#""] && ! [[str stringByTrimmingCharactersInSet:numberSet] isEqualToString:#""];
if (isAlphaNumericOnly) {
NSLog(#"isAplhaNumericOnly: %#",(isAlphaNumericOnly? #"Yes":#"No"));
}
This is always returning true. I am not getting what is wrong in this.
How about using regular expression:
-(BOOL)isAlphaNumericOnly:(NSString *)input
{
NSString *alphaNum = #"[a-zA-Z0-9]+";
NSPredicate *regexTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", alphaNum];
return [regexTest evaluateWithObject:input];
}
and then use it
if([self isAlphaNumeric:str])
{
NSLog(#"IT IS ALPHA NUMERIC STRING");
}
edit
The same technique can be used to validate passwords, you need only better regex:
-(BOOL)isPasswordStrong:(NSString *)password {
/*
8-20 chars
at least one letter
at least one number OR special character
no more than 3 repeated characters
*/
NSString *strongPass= #"^(?!.*(.)\\1{3})((?=.*[\\d])(?=.*[A-Za-z])|(?=.*[^\\w\\d\\s])(?=.*[A-Za-z])).{8,20}$";;
NSPredicate *regexTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", strongPass];
return [regexTest evaluateWithObject:password];
}
using the regular expression you can create different rules but this can give you a headstart,
Call this Method and modify it accordingly .....
-(BOOL) isPasswordValid:(NSString *)pwd
{
if ( [pwd length]<4 || [pwd length]>20 ) return NO; // too long or too short
NSRange rang;
rang = [pwd rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]];
if ( !rang.length ) return NO; // no letter
rang = [pwd rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]];
if ( !rang.length ) return NO; // no number;
return YES;
}
I guess the problem is in the alphanumericCharacterSet, here is a part from doc:
Informally, this set is the set of all characters used as basic units
of alphabets, syllabaries, ideographs, and digits.
So, I am expecting it would allow the unwanted characters to you.
You may also try using Regex:
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"^[a-z\\d]+$" options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger matches = [regex numberOfMatchesInString:str options:NSMatchingReportCompletion range:NSMakeRange(0, [str length])];
BOOL hasMatches = (matches > 0) && !error;
Try this
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSCharacterSet *charactersToBlock = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
return ([string rangeOfCharacterFromSet:charactersToBlock].location == NSNotFound);
}
Try this :
NSCharacterSet *blockedCharacters = [[[NSCharacterSet alphanumericCharacterSet] invertedSet] retain];
- (BOOL)textField:(UITextField *)field shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)characters
{
return ([characters rangeOfCharacterFromSet:blockedCharacters].location == NSNotFound);
}

Find one string in another with case insensitive in Objective-C

My question is similar to How do I check if a string contains another string in Objective-C?
How can I check if a string (NSString) contains another smaller string but with ignoring case?
NSString *string = #"hello bla bla";
I was hoping for something like:
NSLog(#"%d",[string containsSubstring:#"BLA"]);
Anyway is there any way to find if a string contains another string with ignore case ? But please do not convert both strings to UpperCase or to LowerCase.
As similar to the answer provided in the link, but use options.
See - (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask in Apple doc
NSString *string = #"hello bla bla";
if ([string rangeOfString:#"BLA" options:NSCaseInsensitiveSearch].location == NSNotFound)
{
NSLog(#"string does not contain bla");
}
else
{
NSLog(#"string contains bla!");
}
From iOS 8 you can add the containsString: or localizedCaseInsensitiveContainsString method to NSString.
if ([string localizedCaseInsensitiveContainsString:#"BlA"]) {
NSLog(#"string contains Case Insensitive bla!");
} else {
NSLog(#"string does not contain bla");
}
NSString *string = #"hello BLA";
if ([string rangeOfString:#"bla" options:NSCaseInsensitiveSearch].location == NSNotFound) {
NSLog(#"string does not contain bla");
} else {
NSLog(#"string contains bla!");
}
The method
[string rangeOfString:#"bla" options:NSCaseInsensitiveSearch];
should help you.
You can use -(NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask; to get a range for a substring, the mask parameter is used to specify case insensitive match.
Example :
NSRange r = [str rangeOfString:#"BLA"
options:NSCaseInsensitiveSearch];
As stated in the documentation, the method returns a range like {NSNotFound, 0} when the substring isn't found.
BOOL b = r.location == NSNotFound;
Important this method raises an exception if the string is nil.
For Swift 4:
extension String {
func containsCaseInsensitive(string : String) -> Bool {
return self.localizedCaseInsensitiveContains(string)
}
}
Usage:
print("Hello".containsCaseInsensitive(string: "LLO"))
Output:
true

NSString: Find parts of string in another string

I know how to find a string in another string, that is easy. But in this case I want to find John Smith within the allProfessors string. So I figured I could just split the string and search for both parts, which works how I want:
NSString *fullName = #"John Smith";
NSArray *parts = [fullName componentsSeparatedByString:#" "];
NSString *allProfessors = #"Smith, John; Clinton, Bill; Johnson, John";
NSRange range = [[allProfessors lowercaseString] rangeOfString:[[parts objectAtIndex:0] lowercaseString]];
NSRange range2 = [[allProfessors lowercaseString] rangeOfString:[[parts objectAtIndex:1] lowercaseString]];
if(range.location != NSNotFound && range2.location != NSNotFound) {
NSLog(#"Found");
} else {
NSLog(#"Not Found");
}
What I want to know is, is this the BEST way to do this or is there a more preferred method to do what I want?
In addition to this, what if my fullName is longer than my allProfessors name, such as:
NSString *fullName = #"Gregory Smith";
NSString *allProfessors = #"Smith, Greg; Clinton, Bill; Johnson, John";
I still want there to be a match for Greg Smith and Gregory Smith.
You could use regular expressions, which I prefer to use. See RegexKitLite.
With RegexKitLite, you could use a regular expression like (untested):
NSString *regEx = #"(?i)Smith,\\s*\\w";
NSArray *matchingStrings = [allProfessors componentsMatchedByRegex:regEx];
if ([matchingStrings count] == 0) // not found!
{
[...]
}
else
{
[...]
}
Using RegexKitLite you could alternatively have used [NSString stringByMatching:(NSString*)].
You can really do a lot with regular expression. There are a ton of different functions available through Using RegexKitLite. The regular expression above should find people with the last name of Smith.
Regular Expression explained:
(?i) make this case insensitive
Smith matches last name of Smith. Obviously you could change this to anything
, match a comma
\\s* match any number of spaces (greedy)
\\w match a word
Also, you could use [NSString rangeOfString:options:] function like:
if ([myString rangeOfString:#"John" options:NSCaseInsensitiveSearch].location != NSNotFound &&
[myString rangeOfString:#"Smith" options:NSCaseInsensitiveSearch].location != NSNotFound)
{
NSLog(#"Found");
}
else
{
NSLog(#"Not Found");
}
Also see similar functions like [rangeOfString:options:range:locale:] so that you can do case insensitive searches and even specify a locale.

How to replace string occur in NSMutableString from another string

I have a NSMutableString that contains a word twice.(e.g. /abc ...................... /abc).
Now I want to replace these two occurrences of /abc with /xyz. I want to replace only first and last occurence no other occurences.
- (NSUInteger)replaceOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement
options:(NSStringCompareOptions)opts
range:(NSRange)searchRange
I find this instance method of NSMutableString but I am not able to use it in my case.
Anyone have any solution??
You can first find the two ranges and then replace them seperately:
NSMutableString *s = [NSMutableString stringWithString:#"/abc asdfpjklwe /abc"];
NSRange a = [s rangeOfString:#"/abc"];
NSRange b = [s rangeOfString:#"/abc" options:NSBackwardsSearch];
if ((a.location == NSNotFound) || (b.location == NSNotFound)) {
// at least one of the substrings not present
} else {
[s replaceCharactersInRange:a withString:#"/xyz"];
[s replaceCharactersInRange:b withString:#"/xyz"];
}