Objective c: Comparing String on basis of common pattern - objective-c

I have two strings.
NSString *a=#"1_2";
NSString *b=#"1_3";
I want to compare these two string .I want that these two string should be equal. By equal I mean first two characters are the same.
Is there any method which can compare these two string?

Here's a method to compare only the first two characters:
- (NSComparisonResult)compareFirstTwoCharactersOf:(NSString *)str1 with:(NSString *)str2
{
if ([str1 length] < 2) {
// Receiver too short, fall back.
return [str1 compare:str2];
} else {
return [str1 compare:str2 options:0 range:NSMakeRange(0, 2)];
}
}

if ([a isEqualToString:b]) {
NSLog(#"equal");
}

if ([[a substringToIndex:2] isEqualToString:[b substringToIndex:2]]) {
NSLog(#"equal");
}

You should use regular expressions. You should create a regular expression that corresponds to "digit underscore digit", and then if a and b fit the expression then they both are "equal" the way you want them to be, not literally equal of course.
Check this out:
https://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html
As an example, a regular expression that matches "digit underscore digit" should be: \d_\d
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\d_\d" options:0 error:NULL];
NSString *a = #"1_2";
NSString *b = #"1_3";
NSTextCheckingResult *matchA = [regex firstMatchInString:a options:0 range:NSMakeRange(0, [a length])];
NSTextCheckingResult *matchB = [regex firstMatchInString:b options:0 range:NSMakeRange(0, [b length])];
if(matchA && matchB){
//Strings match the same pattern
}

Related

How can I replace one pair of character with multiple occurrence in a string?

Original String is: This is a sentence with (noun) (verb) (adverb).
Original sentence has three occurrence of (). I need the last one intact but replace rest with #""
Required String: This is a sentence with (adverb).
I can do it with NSRange but I am looking for NSRegularExpression pattern.
Also which is more efficient, one with NSRange or the NSRegularExpression.
CODE
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\\(.*?\\)" options:NSRegularExpressionCaseInsensitive error:NULL];
NSString *newString = [regex stringByReplacingMatchesInString:modify options:0 range:NSMakeRange(0, [modify length]) withTemplate:#""];
Output:: This is a sentence with
You can obtain the match ranges themselves and do the replacement manually, ignoring the last one.
NSMutableString* newString = [modify mutableCopy];
NSArray<NSTextCheckingResult*>* matches = [regex matchesInString:newString options:0 range:NSMakeRange(0, newString.length)];
if (matches.count >= 2)
{
// Enumerate backwards so that each replacement doesn't invalidate the other ranges
for (NSInteger i = matches.count - 2; i >= 0; i--)
{
NSTextCheckingResult* result = matches[i];
[newString replaceCharactersInRange:result.range withString:#""];
}
}

Objective-C regex to remove part of string

Hi im trying to remove som HTML string from a web response. I want to remove <pre><a style="" name="output-line-1">1</a>, were the who instances of number "1"varies, but is always a digit. but how do i write the regex method for removing this? Below is what i have got so far:
-(NSString *)stringByStrippingHTML:(NSString*)str
{
NSRange r;
while ((r = [str rangeOfString:#"/^<pre><a style=\"\"name=\"output-line-([0-9])\">([0-9])</a>" options:NSRegularExpressionSearch]).location != NSNotFound){
str = [str stringByReplacingCharactersInRange:r withString:#""];
}
}
Basically I want to remove a substring with random number in it... In some instances of the substring the 1 is replaced, so that any similar string gets acknowledged, for example it could be output-line-999. How do i combine the range of string so i can both describe the string and specify to find any similar string with any number?
I want to remove both the HTML and the numbers.
This regular expression should work:
[str rangeOfString:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>" options:NSRegularExpressionSearch];
I thnk the problem is that there ins't a space before name in your reg expression
Using your original while loop, you can:
-(NSString *)stringByStrippingHTML:(NSString*)str
{
NSRange r;
while ((r = [str rangeOfString:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>" options:NSRegularExpressionSearch]).location != NSNotFound)
{
str = [str stringByReplacingCharactersInRange:r withString:#""];
}
}
Or you can use NSRegularExpression:
NSMutableString *input = ...
NSError *error;
NSRegularExpression *regex;
regex = [NSRegularExpression regularExpressionWithPattern:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>"
options:0
error:&error];
if (error)
{
NSLog(#"error=%#",error);
return;
}
[regex replaceMatchesInString:input
options:0
range:NSMakeRange(0, [input length])
withTemplate:#""];

Objective C NSString Validation

i have a NSString which has user entered UITextField value, here i need to validate whether the string only contains values like
'a to z' , 'A to z' , '1 to 9'.
i don't want any other characters other than these... Please help me out...
i have use NSNumberFormatter for Numbers and NSScanner for Strings, but how to validate both at a time.
Make UITextField delegate and paste this below code :-
// in -init, -initWithNibName:bundle:, or similar
NSCharacterSet *blockedCharacters = [[[NSCharacterSet alphanumericCharacterSet] invertedSet] retain];
- (BOOL)textField:(UITextField *)field shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)characters
{
return ([characters rangeOfCharacterFromSet:blockedCharacters].location == NSNotFound);
}
// in -dealloc
[blockedCharacters release];
Hope it helps you
you can use an NSRegularExpression like so:
NSString *string1 = #"abc123";
NSString *string2 = #"!abc123";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[^a-z0-9]" options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:string1 options:0 range:NSMakeRange(0, [string1 length])];
NSLog(#"string 1 matches: %ld", numberOfMatches);
numberOfMatches = [regex numberOfMatchesInString:string2 options:0 range:NSMakeRange(0, [string1 length])];
NSLog(#"string 2 matches: %ld", numberOfMatches);
and change the pattern #"[^a-z0-9]" to suit the characters you want to check for. The ^ means "not in this set", so if any matches are found the field should fail validation.

In objective-c is it possible to get the position of a regex match within the string

If I have the string "Hello World", is it possible to use NSRegularExpression with the pattern #"World" to get the position of the match, i.e. in the "Hello World" example the position/index of the match should be "6"?
in php I'd use preg_match with the "PREG_OFFSET_CAPTURE" flag to achieve this, does objective-c support this?
You can do it the Cocoa way:
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:#"world" options:0 error:NULL];
// omitted error checking for the sake of simplicity
NSString *str = #"Hello world!";
[regex enumerateMatchesInString:str
options:0
range:NSMakeRange(0, str.length)
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
{
NSLog(#"Match at [%d, %d]", result.range.location, result.range.length);
}];
[regex release];
Or the POSIX way (this may be convenient for you, since you want only one match, and this function/method returns the match range directly):
#include <regex.h>
- (NSRange)matchString:(NSString *)string toRegex:(NSString *)regex
{
regex_t regex_obj;
regmatch_t match;
const char *regex_str;
const char *match_str;
int error;
regex_str = [regex UTF8String];
error = regcomp(&regex_obj, regex_str, REG_EXTENDED);
if (error)
{
return NSMakeRange(NSNotFound, 0);
}
match_str = [string UTF8String];
error = regexec(&regex_obj, match_str, 1, &match, 0);
if (error)
{
return NSMakeRange(NSNotFound, 0);
}
regfree(&regex_obj);
return NSMakeRange(match.rm_so, match.rm_eo - match.rm_so);
}
This is somewhat long in Cocoa, but you can do it:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"world"
options:NSRegularExpressionSearch
error:&error];
NSString *str = #"Hello, world!";
NSTextCheckingResult *match = [regex firstMatchInString:str
options:0
range:NSMakeRange(0, [str length])];
if (match) {
NSRange matchRange = [match range];
NSLog(#"%lu", matchRange.location);
}
This prints 7.
If you're going to make a lot of use of RegEx's, I recommend looking at RegexKit or RegexKitLite.
Yes it is possible. You can use the NSRegularExpression method, rangeOfFirstMatchInString:options:range: which returns the range of the first match. You could also do this with the NSString method rangeOfString: if you don't need to use REGEX.

Why does NSRegularExpression not honor capture groups in all cases?

Main problem: ObjC can tell me there were six matches when my pattern is, #"\\b(\\S+)\\b", but when my pattern is #"A b (c) or (d)", it only reports one match, "c".
Solution
Here's a function which returns the capture groups as an NSArray. I'm an Objective C newbie so I suspect there are better ways to do the clunky work than by creating a mutable array and assigning it at the end to an NSArray.
- (NSArray *)regexWithResults:(NSString *)haystack pattern:(NSString *)strPattern
{
NSArray *ar;
ar = [[NSArray alloc] init];
NSError *error = NULL;
NSArray *arTextCheckingResults;
NSMutableArray *arMutable = [[NSMutableArray alloc] init];
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:strPattern
options:NSRegularExpressionSearch error:&error];
arTextCheckingResults = [regex matchesInString:haystack
options:0
range:NSMakeRange(0, [haystack length])];
for (NSTextCheckingResult *ntcr in arTextCheckingResults) {
int captureIndex;
for (captureIndex = 1; captureIndex < ntcr.numberOfRanges; captureIndex++) {
NSString * capture = [haystack substringWithRange:[ntcr rangeAtIndex:captureIndex]];
//NSLog(#"Found '%#'", capture);
[arMutable addObject:capture];
}
}
ar = arMutable;
return ar;
}
Problem
I am accustomed to using parentheses to match capture groups in Perl in a manner like this:
#!/usr/bin/perl -w
use strict;
my $str = "This sentence has words in it.";
if(my ($what, $inner) = ($str =~ /This (\S+) has (\S+) in it/)) {
print "That $what had '$inner' in it.\n";
}
That code will produce:
That sentence had 'words' in it.
But in Objective C, with NSRegularExpression, we get different results. Sample function:
- (void)regexTest:(NSString *)haystack pattern:(NSString *)strPattern
{
NSError *error = NULL;
NSArray *arTextCheckingResults;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:strPattern
options:NSRegularExpressionSearch
error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:haystack options:0 range:NSMakeRange(0, [haystack length])];
NSLog(#"Pattern: '%#'", strPattern);
NSLog(#"Search text: '%#'", haystack);
NSLog(#"Number of matches: %lu", numberOfMatches);
arTextCheckingResults = [regex matchesInString:haystack options:0 range:NSMakeRange(0, [haystack length])];
for (NSTextCheckingResult *ntcr in arTextCheckingResults) {
NSString *match = [haystack substringWithRange:[ntcr rangeAtIndex:1]];
NSLog(#"Found string '%#'", match);
}
}
Calls to that test function, and the results show it is able to count the number of words in the string:
NSString *searchText = #"This sentence has words in it.";
[myClass regexTest:searchText pattern:#"\\b(\\S+)\\b"];
Pattern: '\b(\S+)\b'
Search text: 'This sentence has words in it.'
Number of matches: 6
Found string 'This'
Found string 'sentence'
Found string 'has'
Found string 'words'
Found string 'in'
Found string 'it'
But what if the capture groups are explicit, like so?
[myClass regexTest:searchText pattern:#".*This (sentence) has (words) in it.*"];
Result:
Pattern: '.*This (sentence) has (words) in it.*'
Search text: 'This sentence has words in it.'
Number of matches: 1
Found string 'sentence'
Same as above, but with \S+ instead of the actual words:
[myClass regexTest:searchText pattern:#".*This (\\S+) has (\\S+) in it.*"];
Result:
Pattern: '.*This (\S+) has (\S+) in it.*'
Search text: 'This sentence has words in it.'
Number of matches: 1
Found string 'sentence'
How about a wildcard in the middle?
[myClass regexTest:searchText pattern:#"^This (\\S+) .* (\\S+) in it.$"];
Result:
Pattern: '^This (\S+) .* (\S+) in it.$'
Search text: 'This sentence has words in it.'
Number of matches: 1
Found string 'sentence'
References:
NSRegularExpression
NSTextCheckingResult
NSRegularExpression matching options
I think if you change
// returns the range which matched the pattern
NSString *match = [haystack substringWithRange:ntcr.range];
to
// returns the range of the first capture
NSString *match = [haystack substringWithRange:[ntcr rangeAtIndex:1]];
You will get the expected result, for patterns containing a single capture.
See the doc page for NSTextCheckingResult:rangeAtIndex:
A result must have at least one range, but may optionally have more (for example, to represent regular expression capture groups).
Passing rangeAtIndex: the value 0 always returns the value of the the range property. Additional ranges, if any, will have indexes from 1 to numberOfRanges-1.
Change the NSTextCheckingResult:
- (void)regexTest:(NSString *)haystack pattern:(NSString *)strPattern
{
NSError *error = NULL;
NSArray *arTextCheckingResults;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:strPattern
options:NSRegularExpressionSearch
error:&error];
NSRange stringRange = NSMakeRange(0, [haystack length]);
NSUInteger numberOfMatches = [regex numberOfMatchesInString:haystack
options:0 range:stringRange];
NSLog(#"Number of matches for '%#' in '%#': %u", strPattern, haystack, numberOfMatches);
arTextCheckingResults = [regex matchesInString:haystack options:NSRegularExpressionCaseInsensitive range:stringRange];
for (NSTextCheckingResult *ntcr in arTextCheckingResults) {
NSRange matchRange = [ntcr rangeAtIndex:1];
NSString *match = [haystack substringWithRange:matchRange];
NSLog(#"Found string '%#'", match);
}
}
NSLog output:
Found string 'words'