Regex number of matches is always zero - objective-c

I want to check a UITextField text with a format like "G12-123456".
Rules are simple;
First character must be upper case letter.
The 2nd and 3rd must be number.
Fourth must be "-" character.
The last six must be only numbers.
Below code not work, number of matches always returns zero.
I also tried regex as "[A-Z0-9]{3}-[0-9]{6}"
NSString * myRegex = #"[A-Z][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:myRegex
options:NSRegularExpressionCaseInsensitive
error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:string
options:NSMatchingReportProgress
range:NSMakeRange(0, [string length])];
This one works with same code [^a-zA-Z0-9] -> Check whether an NSString contains a special character and a digit.
Any help would be appreciated.

First of all basically your code is supposed to work.
However both options are nonsensical. If you want to check for uppercase letter you must not pass NSRegularExpressionCaseInsensitive and NSMatchingReportProgress affects only the block based API.
In both cases pass 0.
The pattern can be written more efficient
NSString *myRegex = #"[A-Z]\\d{2}-\\d{6}";
NSError *error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:myRegex
options:0
error:&error];
if {error) {
NSLog(#"%#", error);
} else {
NSUInteger numberOfMatches = [regex numberOfMatchesInString:string
options:0
range:NSMakeRange(0, [string length])];
NSLog(#"%lu", numberOfMatches);
}
If the regex must match the entire string add the start - end anchors.
NSString *myRegex = #"^[A-Z]\\d(2)-\\d{6}$";
If numberOfMatches is zero please check if the hyphen character is the standard one (ASCII 45, hex 0x2D).

Related

Regular expression to match multiple occurrences of characters between delimiters

I'm trying to use NSRegularExpression to find multiple occurrences of substrings that are delimited by a pair of % characters, for example if I want to extract "%FirstOccurence%enter code here" as a substring from the following:
"stuff %FirstOccurence% more stuff"
Then I can do this:
NSString* const pattern = #"[%].+[%]";
NSRegularExpression* regex = [[NSRegularExpression alloc] initWithPattern:pattern
options:0
error:nil];
NSRange range = NSMakeRange(0, [testData length]);
NSTextCheckingResult *textCheckingResult = [regex firstMatchInString:testData options:0 range: range];
However if the string contains something like this:
"stuff %FirstOccurence% more stuff %Second Occurrence% yet more stuff"
Then my regex will match this: "%FirstOccurence% more stuff %Second Occurrence%" i.e. the NSTextCheckingResult will contain one range.
What should the regex/code be to make the NSTextCheckingResult contain two ranges of %FirstOccurence% and %Second Occurrence% rather than the one larger range?
It appears you want to be calling matchesInString:options:range: which returns all the matching results.
NSArray *matches = [regex matchesInString:string
options:0
range:NSMakeRange(0, [string length])];
See https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSRegularExpression

RegEx (replaceMatchesInString) does not work

Why does this RegEx with replaceMatchesInString return only "+" instead of "+123"?
NString *phoneNumberCleaned = [NSString stringWithFormat:#"++00123"];
NSString *strRegExPhoneNumberPrefixWrong = #"^([+0]*)\\d*$";
NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:strRegEx options:0 error:nil];
[regEx replaceMatchesInString:phoneNumberCleaned options:0 range:NSMakeRange(0, [phoneNumberCleaned length]) withTemplate:#"+"];
return phoneNumberCleaned;
Thanks
NSString *string = #"++00123";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"^[+0]+(?=\\d*)"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSString *modifiedString = [regex
stringByReplacingMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
withTemplate:#"+"];
return modifiedString;
The problem with your Regex was that ^([+0]*)\\d*$ is also matching the \d* which means, that it also gets replaced (you'd think that it would only replace your capture group, but evidently that isn't so). So you were essentialy replacing any string that matches the above pattern (which was including any trailing numbers), which in your case was the entire number.
What I used in my answer is called a positive lookahead.
^[+0]+(?=\\d*)$
The lookahead basically means that you're looking for zero or more + or 0 that are followed by zero or more digits EXCLUDING the digits from the match. So you only replace the zeroes and pluses, not the digits following them.

NSRegularExpression get only the regex

i have a problem and i don't undestand how to do this ( after 6hours or googling)
i'have a string named "filename" containt this text :"Aachen-Merzbrück EDKA\r\r\nVerkehr"
i want to use regex to only get this part "Aachen-Merzbrück EDKA" but i cant....
here my code :
NSString *expression = #"\\w+\\s[A-Z]{4}";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:&error];
NSString *noAirportString = [regex stringByReplacingMatchesInString:filename options:0 range:NSMakeRange(0, [filename length]) withTemplate:#""];
EDIT :
this one work good :
\S+\s+[A-Z]{4}
but now, how to get only this "Aachen-Merzbrück" EDKA from "Aachen-Merzbrück EDKA\r\r\nVerkehr"
my regex with NSRegularExpression return me the same string ....
A couple of issues in your question:
No need to match city name characters - there are always weird ones around (hyphens, apostrophes, etc.) You can just match the first "line" in your text with a test for the ICAO code as an extra security.
Using stringByReplacingMatchesInString: you actually remove the airport name (and ICAO code) that you want keep.
stringByReplacingMatchesInString: is a hacky (because it deletes things, so you need to make your regexes "negative") shortcut that sometimes works (I use it myself) but which risks confusing things - and future readers.
Having said that, a few changes will fix it:
NSString *filename = #"Aachen-Merzbrück EDKA\r\r\nVerkehr";
// Match anything from the beginning of the line up to a space and 4 upper case letters.
NSString *expression = #"^.+\\s[A-Z]{4}$";
NSError *error = NULL;
//Make sure ^ and $ match line endings,
//and make it case sensitive (the default) to explicitly
//match the 4 upper case characters of the ICAO code
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionAnchorsMatchLines error:&error];
NSArray *matches = [regex matchesInString:filename
options:0
range:NSMakeRange(0, [filename length])];
// Check that there _is_ a match before you continue
if (matches.count == 0) {
// Error
}
NSRange airportNameRange = [[matches objectAtIndex: 0] range];
NSString *airportString = [filename substringWithRange: airportNameRange];
Thanks it's good working, but i use this one, it's work better in my case :
NSString *expression = #"\\S+\\s+[A-Z]{4}";

Regex stringByReplacingMatchesInString

I'm trying to remove any non-alphanumeric character within a string. I tried the following code snippet, but it is not replacing the appropriate character.
NSString *theString = #"\"day's\"";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"^\\B\\W^\\B" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *newString = [regex stringByReplacingMatchesInString:theString options:0 range:NSMakeRange(0, [theString length]) withTemplate:#""];
NSLog(#"the resulting string is %#", newString);
Since there'e a need to preserve the enclosing quotation marks in the string, the regex necessarily becomes a bit complex.
Here is one which does it:
(?:(?<=^")(\W+))|(?:(?!^")(\W+)(?=.))|(?:(\W+)(?="$))
It uses lookbehind and lookahead to match the quotation marks, without including them in the capture group, and hence they will not be deleted in the substitution with the empty string.
The three parts handle the initial quotation mark, all characters in the middle and the last quotation mark, respectively.
It is a bit pedestrian and there has to be a simpler way to do it, but I haven't been able to find it. Others are welcome to chime in!
NSString *theString = #"\"day's\"";
NSString *pattern = #"(?:(?<=^\")(\\W+))|(?:(?!^\")(\\W+)(?=.))|(?:(\\W+)(?=\"$))";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: pattern
options: 0 // No need to specify case insensitive, \W makes it irrelevant
error: &error];
NSString *newString = [regex stringByReplacingMatchesInString: theString
options: 0
range: NSMakeRange(0, [theString length])
withTemplate: #""];
The (?:) construct creates a non-capturing parenthesis, meaning that you can keep the lookbehind (or lookahead) group and "real" capture group together without creating an actual capture group encapsulating the whole parenthesis. Without that you couldn't just substitute an empty string, or it would all be deleted.

capturing a string before and after some data using regular expressions in ObjectiveC

I am relatively new to regex expressions and needed some advice.
The goal is to the get data in the following format into an array:
value=777
value=888
From this data: "value=!##777!##value=##$888*"
Here is my code (Objective C):
NSString *aTestString = #"value=!##777!##value=##$**888***";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"value=(?=[^\d])(\d)" options:0 error:&anError];
So my questions are:
1) Can the regex engine capture data that is split like that? Retrieving the "value=" removing the garbage data in the middle, and then grouping it with its number "777" etc?
2) If this can be done, then is my regex expression valid? value=(?=[^\d])(\d)
The lookahead (?=) is wrong here, you haven't correctly escaped the \d (it becomes \\d) and last but not least you left out the quantifiers * (0 or more times) and + (1 or more times):
NSString *aTestString = #"value=!##777!##value=##$**888***";
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"value=[^\\d]*(\\d+)"
options:0
error:NULL
];
[regex
enumerateMatchesInString:aTestString
options:0
range:NSMakeRange(0, [aTestString length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSLog(#"Value: %#", [aTestString substringWithRange:[result rangeAtIndex:1]]);
}
];
Edit: Here's a more refined pattern. It catches a word before =, then discards non-digits and catches digits afterwards.
NSString *aTestString = #"foo=!##777!##bar=##$**888***";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(\\w+)=[^\\d]*(\\d+)" options:0 error:NULL];
[regex
enumerateMatchesInString:aTestString
options:0
range:NSMakeRange(0, [aTestString length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSLog(
#"Found: %#=%#",
[aTestString substringWithRange:[result rangeAtIndex:1]],
[aTestString substringWithRange:[result rangeAtIndex:2]]
);
}
];
// Output:
// Found: foo=777
// Found: bar=888
Regular expresssions are expressions that match a given pattern. A regular expression could match, say, a string like "value=!##777" using an expression like "value=[##!%^&][0-9]", which says to match the literal "value=", and then any string made up of the characters #, #, !, %, ^, and &, and finally any string made up of digits. But you can't use a single regular expression by itself to get just the parts of the string that you want, i.e. "value=777".
So, one solution would be to create an expression that recognizes strings such as "value=!##777", and then do some further processing on that string to remove the offending characters.
I think you'll be better off using NSScanner to scan the data and extract the parts you want. For example, you can use -scanString:intoString: to get the "value=" part, followed by -scanCharactersFromSet:intoString: to remove the part you don't want, and then call that method again to get the collection of digits.