RegexKitLite - iOS: unrecognized selector - ios

I have a project that must use regular expressions, so I decided to use RegexKitLite, I downloaded it, have added RegexKitLite.m into "Compile Sources", and RegexKitLite.h into "Copy Files" sections. Added libicucore.A.dylib to project Libraries. Imported RegexKitLite.h into my class, and write code (just for test):
NSString *str = #"testing string";
if ([str isMatchedByRegex:#"[^a-zA-Z0-9]"])
{
NSLog(#"Some message here");
}
After that I have error message:
-[__NSCFString isMatchedByRegex:]: unrecognized selector sent to instance 0x1ed45ac0
2013-02-28 19:46:20.732 TextProject[8467:907] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString isMatchedByRegex:]: unrecognized selector sent to instance 0x1ed45ac0'
What I have missed? Please help me..

After some digging there wasn't in fact any Cocoa API to use regex before iOS4 so programmers were using external libraries like RegexKitLite which indeed could be used for iOS.
If you are on iOS4 or later there shouldn't be any reason not to use NSRegularExpression. Class reference description can be found here.
For example with NSRegularExpression your code snippet will look like:
NSString *str = #"testing string";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[^a-zA-Z0-9]" options:NSRegularExpressionCaseInsensitive error:nil];
NSTextCheckingResult *match = [regex firstMatchInString:str options:0 range:NSMakeRange(0, [str length])];
NSRange range = [match rangeAtIndex:0];
if (range.location != NSNotFound)
{
NSString* matchingString = [str substringWithRange:range];
NSLog(#"%#", matchingString);
}

Related

AFNetworking crashing in multilingual app

Ride[source_name]=2152,%20Mohali%20Stadium%20Rd,%20Phase%2010,%20Sector%2064,%20Sahibzada%20Ajit%20Singh%20Nagar,%20Punjab%20160062,%20भारत
This parameter is causing crash while running in Hindi while working fine with Spanish and English. Please suggest me on it. Crash description is as following:-
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not
satisfying: URLString'
Check with this
Objective - C
NSString *string = #"भारत";
NSString *encoded = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
Swift 3.0
let string = "भारत"
let urlString = string.addingPercentEncoding( withAllowedCharacters: . urlUserAllowed)
Output :: %E0%A4%AD%E0%A4%BE%E0%A4%B0%E0%A4%A4
Add below line of code to avoid invalid parameters in url.
NSString *str = ...; // Your URL
NSCharacterSet *set = [NSCharacterSet URLHostAllowedCharacterSet];
NSString *result = [str stringByAddingPercentEncodingWithAllowedCharacters:set];
Deprecated Code Before ios 9.0 :
NSString *str = ...; // Your URL
NSString *urlAsString = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

Objective C - NSRegularExpression with specific substring

I have an NSString which I am checking if there is an NSLog and then I comment it out.
I am using NSRegularExpression and then looping through result.
The code:
-(NSString*)commentNSLogFromLine:(NSString*)lineStr {
NSString *regexStr =#"NSLog\\(.*\\)[\\s]*\\;";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexStr options:NSRegularExpressionCaseInsensitive error:nil];
NSArray *arrayOfAllMatches = [regex matchesInString:lineStr options:0 range:NSMakeRange(0, [lineStr length])];
NSMutableString *mutStr = [[NSMutableString alloc]initWithString:lineStr];
for (NSTextCheckingResult *textCheck in arrayOfAllMatches) {
if (textCheck) {
NSRange matchRange = [textCheck range];
NSString *strToReplace = [lineStr substringWithRange:matchRange];
NSString *commentedStr = [NSString stringWithFormat:#"/*%#*/",[lineStr substringWithRange:matchRange]];
[mutStr replaceOccurrencesOfString:strToReplace withString:commentedStr options:NSCaseInsensitiveSearch range:matchRange];
NSRange rOriginal = [mutStr rangeOfString:#"NSLog("];
if (NSNotFound != rOriginal.location) {
[mutStr replaceOccurrencesOfString:#"NSLog(" withString:#"DSLog(" options:NSCaseInsensitiveSearch range:rOriginal];
}
}
}
return [NSString stringWithString:mutStr];
}
The problem is with the test case:
NSString *str = #"NSLog(#"A string"); NSLog(#"A string2")"
Instead of returning "/*DSLog(#"A string");*/ /*DSLog(#"A string2")*/" it returns: "/*DSLog(#"A string"); NSLog(#"A string2")*/".
The issue is how the Objective-C handles the regular expression. I would expected 2 results in arrayOfAllMatches but instead that I am getting only one. Is there any way to ask Objective-C to stop on the first occurrence of ); ?
The problem is with the regular expression. You are searching for .* inside the parentheses, which causes it to include the first close parenthesis, continue through the second NSLog statement, and go all the way to the final close parentheses.
So what you want to do is something like this:
NSString *regexStr =#"NSLog\\([^\\)]*\\)[\\s]*\\;";
That tells it to include everything inside the parenthesis except for the ) character. Using that regex, I get two matches. (note that you omitted the final ; in your string sample).

Extracting URLs from NSString into NSMutableString

I have a file with the following content:
cool name http://myurl1.tld/subdir/dir/var/ awesome\nanother cool name http://sub.domain.tld/dir/ nice\nsome nice name http://myname.tld/var/folder/ some\n
I read the file with this Objetive-C code:
NSData* data = [NSData dataWithContentsOfFile:[NSString stringWithFormat:#"../files/name.ext"]];
NSString* raw = [[NSString alloc]
initWithBytes:[data bytes]
length:[data length]
encoding:NSUTF8StringEncoding];
To extract all URLs from the above sample I use:
NSDataDetector* detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray* matches = [detector matchesInString:raw options:0 range:NSMakeRange(0, [raw length])];
My goal is to append all extracted URLs into one single string and separate them with a semicolon (without any other stuff from the file) with this loop:
NSMutableString *allURLStrings = [NSMutableString string];
for (NSString *s in matches) {
[allURLStrings appendString:s];
[allURLStrings appendString:#";"];
}
Whenever I try to run the code I get the following output:
terminating with uncaught exception of type NSException (lldb)
I tried to use the loop like this, but then the substringForCurrMatch only contains a slash (/):
NSMutableString * allRepoString = [NSMutableString string];
for (NSTextCheckingResult *s in matches) {
NSString* substringForCurrMatch = [s.URL path];
[allRepoString appendString:substringForCurrMatch];
[allRepoString appendString:#";"];
}
When I inspect s in the loop it shows me the correct object:
Is there a way to get this code working?
EDIT complete error message:
2016-08-11 23:00:19.272 AppName[34831:2892247] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[fetchurlsource allURLStrings]: unrecognized selector sent to instance 0x14c55ea00'
*** First throw call stack:
(0x181fa2db0 0x181607f80 0x181fa9c4c 0x181fa6bec 0x181ea4c5c 0x1000e8b6c 0x1000e8ee0 0x187100c40 0x187100844 0x18710759c 0x187104a88 0x18717afa4 0x1873a63ac 0x1873aa5f0 0x1873a7764 0x1839437ac 0x183943618 0x1839439c8 0x181f5909c 0x181f58b30 0x181f56830 0x181e80c50 0x18716f94c 0x18716a088 0x1000edb10 0x181a1e8b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
None of the code you posted so far can result in the exception you posted.
But the following code is incorrect:
NSMutableString * allRepoString = [NSMutableString string];
for (NSTextCheckingResult *s in matches) {
NSString* substringForCurrMatch = [s.URL path];
[allRepoString appendString:substringForCurrMatch];
[allRepoString appendString:#";"];
}
You do not want to call the path method on s.URL. To get the full URL as a string, use absoluteString. This will give you the URL as a string. path just gives you the path portion of the URL.
NSMutableString * allRepoString = [NSMutableString string];
for (NSTextCheckingResult *s in matches) {
NSString* substringForCurrMatch = [s.URL absoluteString];
[allRepoString appendString:substringForCurrMatch];
[allRepoString appendString:#";"];
}

Why does Length not work on a NSString?

I am trying to check the length of string, but I get unrecognized selector when the code is executed and hits the IF statement.
THE VALUE IN THE DICTIONARY IS A STRING.
NSString * checkString = [myDictionary objectForKey:#"somekey"];
NSLog(#"length: %lu", (unsigned long)[checkString length]);
if([checkString length] > 0){
}
ERROR From console:
length: 0
[__NSCFNumber length]: unrecognized selector sent to instance
For simplicity:
NSString * checkString = #"my string"; //[myDictionary objectForKey:#"somekey"];
NSLog(#"length: %lu", (unsigned long)[checkString length]);
if([checkString length] > 0){
}
length: 9
[__NSCFNumber length]: unrecognized selector sent to
instance
Why?
The error says that your instance is not a NSString but a NSNumber. That's probably because you stored a NSNumber in [myDictionary objectForKey:#"somekey"].
Try to put [yourValueThatYouThinkItsAString stringValue] in the place where you store this value.
I tried your code and I'm not getting error with it (with #"my string" value).
What you can try :
NSString *checkString = [[myDictionary objectForKey:#"somekey"] stringValue];
NSLog(#"length: %lu", (unsigned long)[checkString length]);
if([checkString length] > 0){
}
PS : in your NSLog() you've got a additional argument, remove it.
The reason the length is not working on NSString* is that it's not NSString*. Despite the cast, which Objective-C cannot verify, the object in your dictionary is NSNumber*, not NSString*. That is why the code compiles, but fails to run.
[myDictionary objectForKey:#"somekey"] call returns id, a generic object reference. That is why Objective-C must trust you when you perform a cast to NSString* that the object at "somekey" is actually a string.
It does not fail in NSLog because you made a mistake that prevents the length from being evaluated. Change NSLog to see it fail:
NSLog(#"length: %lu", (unsigned long)[checkString length]);
If you have XCode 7 or newer, you can use lightweight generics to help Objective-C with type checking. You can specify object types for keys and values in your dictionary, so that the compiler could catch invalid casts for you:
NSDictionary<NSString*,NSString*> *myDictionary = ...

NSRegularExpression not working properly

Hi i'm having problems where if in the string the there isn't a phone number and the NSRegularExpression cant find anything the app crashes but when it does find the phone number it in the string its works fine with no problems. How can i stop it from crashing.
NSRegularExpression *phoneexpression = [NSRegularExpression regularExpressionWithPattern:#"\\d{4}-\\d{4}"options:NSRegularExpressionCaseInsensitive error:NULL];
NSString *phString = TextString;
NSString *PH = [phString substringWithRange:[phoneexpression rangeOfFirstMatchInString:phString options:NSMatchingCompleted range:NSMakeRange(0, [phString length])]];
I think this is the problem
NSString *PH = [phString substringWithRange:[phoneexpression rangeOfFirstMatchInString:phString options:NSMatchingCompleted range:NSMakeRange(0, [phString length])]];
I guess you get a NSRangeException.
Try it this way:
NSString *PH = nil;
NSRegularExpression *phoneexpression = [NSRegularExpression regularExpressionWithPattern:#"\\d{4}-\\d{4}"options:NSRegularExpressionCaseInsensitive error:NULL];
NSString *phString = TextString;
NSRange rg = [phoneexpression rangeOfFirstMatchInString:phString options:NSMatchingCompleted range:NSMakeRange(0, [phString length])];
if(rg.location != NSNotFound)
PH = [phString substringWithRange:rg];
It is important that you check the returned range before passing it to substringWithRange.
See this reference for more information: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/occ/instm/NSString/substringWithRange:
EDIT:
Also check that the returned range from rangeOfFirstMatchInString does not violate the boundary limitations documented in the reference:
Raises an NSRangeException if (aRange.location - 1) or
(aRange.location + aRange.length - 1) lies beyond the end of the
receiver.

Resources