Check Objective-C String for specific characters - ios

For an app I'm working on, I need to check if a text field contains only the letters A, T, C, or G. Furthermore, I would like to make specialized error messages for any other inputed characters. ex) "Don't put in spaces." or "The letter b isn't an accepted value." I have read a couple other posts like this, but they are alphanumeric, I only want specified characters.

One approach for you, far from unique:
NString has methods to find substrings, represented as an NSRange of location & offset, made up from characters in a given NSCharacterSet.
The set of what should be in the string:
NSCharacterSet *ATCG = [NSCharacterSet characterSetWithCharactersInString:#"ATCG"];
And the set of what shouldn't:
NSCharacterSet *invalidChars = [ATCG invertedSet];
You can now search for any range of characters consisting of invalidChars:
NSString *target; // the string you wish to check
NSRange searchRange = NSMakeRange(0, target.length); // search the whole string
NSRange foundRange = [target rangeOfCharacterFromSet:invalidChars
options:0 // look in docs for other possible values
range:searchRange];
If there are no invalid characters then foundRange.location will be equal to NSNotFound, otherwise you change examine the range of characters in foundRange and produce your specialised error messages.
You repeat the process, updating searchRange based on foundRange, to find all the runs of invalid characters.
You could accumulate the found invalid characters into a set (maybe NSMutableSet) and produce the error messages at the end.
You can also use regular expressions, see NSRegularExpressions.
Etc. HTH
Addendum
There is a really simple way to address this, but I did not give it as the letters you give suggest to me you may be dealing with very long strings and using provided methods as above may be a worthwhile win. However on second thoughts after your comment maybe I should include it:
NSString *target; // the string you wish to check
NSUInteger length = target.length; // number of characters
BOOL foundInvalidCharacter = NO; // set in the loop if there is an invalid char
for(NSUInteger ix = 0; ix < length; ix++)
{
unichar nextChar = [target characterAtIndex:ix]; // get the next character
switch (nextChar)
{
case 'A':
case 'C':
case 'G':
case 'T':
// character is valid - skip
break;
default:
// character is invalid
// produce error message, the character 'nextChar' at index 'ix' is invalid
// record you've found an error
foundInvalidCharacter = YES;
}
}
// test foundInvalidCharacter and proceed based on it
HTH

Use NSRegulareExpression like this.
NSString *str = #"your input string";
NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:#"A|T|C|G" options:0 error:nil];
NSArray *matches = [regEx matchesInString:str options:0 range:NSMakeRange(0, str.length)];
for (NSTextCheckingResult *result in matches) {
NSLog(#"%#", [str substringWithRange:result.range]);
}
Also for the options parameter you have to look in the documentation to pick one that fits.

Look at the NSRegularExpression class reference.
Visit: https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html

Related

iOS - NSString regex match

I have a string for example:
NSString *str = #"Strängnäs"
Then I use a method for replace scandinavian letters with *, so it would be:
NSString *strReplaced = #"Str*ngn*s"
I need a function to match str with strReplaced. In other words, the * should be treated as any character ( * should match with any character).
How can I achieve this?
Strängnäs should be equal to Str*ngn*s
EDIT:
Maybe I wasn't clear enough. I want * to be treated as any character. So when doing [#"Strängnäs" isEqualToString:#"Str*ngn*s"] it should return YES
I think the following regex pattern will match all non-ASCII text considering that Scandinavian letters are not ASCII:
[^ -~]
Treat each line separately to avoid matching the newline character and replace the matches with *.
Demo: https://regex101.com/r/dI6zN5/1
Edit:
Here's an optimized pattern based on the above one:
[^\000-~]
Demo: https://regex101.com/r/lO0bE9/1
Edit 1: As per your comment, you need a UDF (User defined function) that:
takes in the Scandinavian string
converts all of its Scandinavian letters to *
takes in the string with the asterisks
compares the two strings
return True if the two strings match, else false.
You can then use the UDF like CompareString(ScanStr,AsteriskStr).
I have created a code example using the regex posted by JLILI Amen
Code
NSString *string = #"Strängnäs";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[^ -~]" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *modifiedString = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:#"*"];
NSLog(#"%#", modifiedString);
Output
Str*ngn*s
Not sure exactly what you are after, but maybe this will help.
The regular expression pattern which matches anything is. (dot), so you can create a pattern from your strReplaced by replacing the *'s with .'s:
NSString *pattern = [strReplaced stringByReplacingOccurencesOfString:#"*" withString:"."];
Now using NSRegularExpression you can construct a regular expression from pattern and then see if str matches it - see the documentation for the required methods.

Checking for a valid Hebrew regex return always YES

I've a certain regex pattern to check against.
Valid result is is only Hebrew language, letters, marks etc.
//////////Regex//////////
static NSString *const HEBREW_NUMBERS_NON_NUMERIC_CHAR = #"([\u0590-\u05FF]*|[0-9]*|[\\s]*|[.-:;,?!/&*()+=_'\"]*)+";
+ (BOOL)hasValidOpenLine:(NSString *)openLine
{
if (openLine.length >= MIN_NUMBER_OF_CHARACTERS_IN_OPEN_LINE || openLine.length <= MAX_NUMBER_OF_CHARACTERS_IN_OPEN_LINE) {
NSError *errorRegex;
NSRegularExpression *regexOpenLine = [[NSRegularExpression alloc] initWithPattern:HEBREW_NUMBERS_NON_NUMERIC_CHAR
options:0
error:&errorRegex];
NSRange range = NSMakeRange(0, openLine.length);
if ([regexOpenLine numberOfMatchesInString:openLine options:0 range:range] > 0) {
return YES;
}
}
return NO;
}
But no matter what I type, it always return me YES even for only English string.
There may be two things going wrong here, depending on your test string. First off, the stars in your regex allow for empty matches against strings which would otherwise not match, which is why your regex might match English strings — matching your regex on #"Hello, world!" returns {0, 0}, a range whose location is not NSNotFound, but whose length is zero.
The other issue is that you're not anchoring your search. This will allow the regex to match against singular characters in strings that would otherwise not match (e.g. the , in #"Hello, world!"). What you need to do is anchor the regex so that the whole string has to match, or else the regex rejects it.
Your modified code can look something like this:
static NSString *const HEBREW_NUMBERS_NON_NUMERIC_CHAR = #"([\u0590-\u05FF]|[0-9]|[\\s]|[.-:;,?!/&*()+=_'\"])+";
+ (BOOL)hasValidOpenLine:(NSString *)openLine
{
if (openLine.length >= MIN_NUMBER_OF_CHARACTERS_IN_OPEN_LINE || openLine.length <= MAX_NUMBER_OF_CHARACTERS_IN_OPEN_LINE) {
NSError *errorRegex;
NSRegularExpression *regexOpenLine = [[NSRegularExpression alloc] initWithPattern:HEBREW_NUMBERS_NON_NUMERIC_CHAR
options:0
error:&errorRegex];
if ([regexOpenLine numberOfMatchesInString:openLine options:NSMatchingAnchored range:NSMakeRange(0, openLine.length)] > 0) {
return YES;
}
}
return NO;
}
This will now match against strings like #"שלום!", and not strings like #"Hello, world!" or #"Hello: היי", which is what I assume you're going for.
In the future, if you're looking to debug regexes, use -[NSRegularExpression rangeOfFirstMatchInString:options:range:] or -[NSRegularExpression enumerateMatchesInString:options:range:usingBlock:]; they can help you find matches that may cause your regex to accept unnecessarily.

How can i trim a blank(empty) line in NSString?

I have textView where user can add text in new line. but when user enter multiple new line and not enter a any text then i want skip all that line and just use only one new line.
I have String like below.
Hello,
How r u?
I want a string like this
Hello
How r u?
I have tried this but not working
strContects=[strContects stringByReplacingOccurrencesOfString:#"\n\n" withString:#"\n"];
How can i do this?
Hope u will understand?
You can replace multiple occurrence of omit multiple newline characters with single one by following regular expressions code
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\n+" options:0 error:NULL];
NSString *newString = [regex stringByReplacingMatchesInString:myString options:0 range:NSMakeRange(0, [myString length]) withTemplate:#"\n"];
this will print
Hello,
How r u? //in new line(all \n omitted with single \n)
If the goal here is removing all blank lines - not just consolidating multiple newlines - then it is worth noting the accepted answer wont remove an initial blank line in the string; eg "\nHello..."
A bit more involved, but try this category:
- (NSString*)stringByRemovingBlankLines
{
NSScanner *scan = [NSScanner scannerWithString:self];
NSMutableString *string = NSMutableString.new;
while (!scan.isAtEnd) {
[scan scanCharactersFromSet:NSCharacterSet.newlineCharacterSet intoString:NULL];
NSString *line = nil;
[scan scanUpToCharactersFromSet:NSCharacterSet.newlineCharacterSet intoString:&line];
if (line) [string appendFormat:#"%#\n",line];
}
if (string.length) [string deleteCharactersInRange:(NSRange){string.length-1,1}]; // drop last '\n'
return string;
}
(BTW - this can also handle other types of 'newline' characters which the accepted answer does not. This wasn't asked for, but it came up in the comments)

getting certain portion of nsstring

I have string as follows in objective c
NSString *str = #"access_token=E2JmCPLtVySGn-cGGJGGnQ&email=abc#gmail.com";
How can i get only E2JmCPLtVySGn-cGGJGGnQ ?
You can use a Regular Expression (RegEx) to find character patterns.
The pattern matching syntax can be found in the ICU User Guide Regular Expressions
In the example the pattern is: find the first "=" and all characters up to but not including the character "&". In the pattern '(?<=access_token=)" is a look-behind assertion meaning that the "access_token=" must precede the matched text, "[^&]+" the brackets the "[]" mean a character class, the "^" al but the following character, the "+" means one or more.
NSString *str = #"access_token=E2JmCPLtVySGn-cGGJGGnQ&email=abc#gmail.com";
NSString *regexPattern = #"(?<=access_token=)[^&]+";
NSString *found = nil;
NSRange range = [str rangeOfString:regexPattern options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
found = [str substringWithRange:range];
}
NSLog(#"Range: %#", NSStringFromRange(range));
NSLog(#"found: %#", found);
NSLog output if found:
Range: {13, 22}
found: E2JmCPLtVySGn-cGGJGGnQ
There is a method of the NSString class called rangeOfString: that returns an NSRange struct. If you know that your returned value always has the text access_token= and also includes &email and the format is always the same, you can use this rangeOfString: method to sniff out the token.
NSRange accessTokenRange = [str rangeOfString:#"access_token="];
//this would return (0,13) for index:0, length: 13
NSRange emailRange = [str rangeOfString:#"&email="];
//this would return (34,7)
NSInteger tokenLength = ( emailRange.location + 1 ) - accessTokenRange.length;
//the point where &email begins is at index 34, but it starts at 0
//so it's actually the 35th character
//the access_token= string is 13 characters long, so 35-13 = 22
//so you know that the actual token value is 22 characters long
NSRange trueTokenRange = NSMakeRange(accessTokenRange.length,tokenLength);
NSString *tokenSubstring = [str substringWithRange:trueTokenRange];
I don't think my math is off, zero indexing can introduce off by 1 errors if you're not careful, I usually have NSLog going on each range so I can double check where I need to add or subtract 1. But essentially you'll be starting at the 14th character, which is index 13 of the string, and reading the next 22 characters.

How to validate a phone number with + symbol in objective c?

I am so confused about the regex methods. My requirement is to validate a phone number that may contains + symbol in its prefix. Then all the charactors should be numerals only. For this, how can i create a regular expression in objective c.
I'm late answering, but I found an interesting solution when I recently have had the same problem. It uses the built-in cocoa methods instead of custom regex.
- (BOOL)validatePhoneNumberWithString:(NSString *)string {
if (nil == string || ([string length] < 2 ) )
return NO;
NSError *error;
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber error:&error];
NSArray *matches = [detector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
if ([match resultType] == NSTextCheckingTypePhoneNumber) {
NSString *phoneNumber = [match phoneNumber];
if ([string isEqualToString:phoneNumber]) {
return YES;
}
}
}
return NO;
}
I wouldn't say this is a definitive answer but it should give you a start.
^\x2b[0-9]+
Will match any string that starts with a '+' and then any amount of numbers greater than 0.
For instance:
+441312002000 - Full phone number matched.
+4413120c2000 - +4413120 is matched.
++441312002000 - No match
441312002000 - No Match
If there are further constraints on length etc then specifiy and I can update the regex. I agree with other poster about using RegexKitLite.
Use RegexKitLite, check the following http://regexkit.sourceforge.net/RegexKitLite/
^\+?[0-9]*$
should do:
^ # start of string
\+? # match zero or one + characters
[0-9]* # match any number of digits
$ # end of string
To use the regex in a string, you'll need to double the backslashes: #"^\\+?[0-9]*$" should work according to other regex examples I've seen, but I don't know Objective-C and may be wrong about this.
This post nicely explains the regex -- http://blog.stevenlevithan.com/archives/validate-phone-number. You have to use "\" instead of "\" to prevent the Objective C preprocessor from interpreting regex escape codes as character string escape codes.
Here is the NSString you would use for the requested match
NSString *northAmRegexWithOptionalLeadingOne = #"^(?:\\+?1[-. ]?)?\\(?([2-9][0-8][0-9])\\)?[-. ]?([2-9][0-9]{2})[-. ]?([0-9]{4})$";
+*[0-9]{length of phone}. Should work.

Resources