How to check if a string contains an URL - iphone

i have text message and I want to check whether it is containing text "http" or URL exists in that.
How will I check it?

NSString *string = #"xxx http://someaddress.com";
NSString *substring = #"http:";
Case sensitive example:
NSRange textRange = [string rangeOfString:substring];
if(textRange.location != NSNotFound){
//Does contain the substring
}else{
//Does not contain the substring
}
Case insensitive example:
NSRange textRange = [[string lowercaseString] rangeOfString:[substring lowercaseString]];
if(textRange.location != NSNotFound){
//Does contain the substring
}else{
//Does not contain the substring
}

#Cyprian offers a good option.
You could also consider using a NSRegularExpression which would give you far more flexibility assuming that's what you need, e.g. if you wanted to match http:// and https://.

Url usually has http or https in it
You can use your custom method containsString to check for those strings.
- (BOOL)containsString:(NSString *)string {
return [self containsString:string caseSensitive:NO];
}
- (BOOL)containsString:(NSString*)string caseSensitive:(BOOL)caseSensitive {
BOOL contains = NO;
if (![NSString isNilOrEmpty:self] && ![NSString isNilOrEmpty:string]) {
NSRange range;
if (!caseSensitive) {
range = [self rangeOfString:string options:NSCaseInsensitiveSearch];
} else {
range = [self rangeOfString:string];
}
contains = (range.location != NSNotFound);
}
return contains;
}
Example :
[yourString containsString:#"http"]
[yourString containsString:#"https"]

Related

iPhone Regex for GUIDs

I was searching around finding some easy regex for iPhone to validate if a NSString is in a valid Hex format, containing only characters from 0-9 and a-f. The same for GUID's. Or is there already a function built in to check if a GUID is valid?
I only found some posts about creating GUIDs. This SO answer is creating GUID's in the format I'm using them.
Sample GUID
ADD2B9F7-A699-4EF3-9A70-130B92154B11
To simplify Zaph's correct answer, just add this method to a category on NSString:
-(BOOL) isGuid {
NSString *regexString = #"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
NSRange guidValidationRange = [self rangeOfString:regexString options:NSRegularExpressionSearch];
return (guidValidationRange.location == 0 && guidValidationRange.length == self.length);
}
One way is to use NSCharacterSet:
NSString *testCharacters = #"ABCDEFabcdef0123456789-";
NSCharacterSet *testCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:testCharacters] invertedSet];
NSString *testString1 = #"ADD2B9F7-A699-4EF3-9A70-130B92154B11";
NSRange range1 = [testString1 rangeOfCharacterFromSet:testCharacterSet];
NSLog(#"testString1: %#", (range1.location == NSNotFound) ? #"Good" : #"Bad");
NSString *testString2 = #"zDD2B9F7-A699-4EF3-9A70-130B92154B11";
NSRange range2 = [testString2 rangeOfCharacterFromSet:testCharacterSet];
NSLog(#"testString2: %#", (range2.location == NSNotFound) ? #"Good" : #"Bad");
NSLog output:
testString1: Good
testString2: Bad
or using REs:
NSString *reString = #"[a-fA-F0-9-]+";
NSString *testString1 = #"ADD2B9F7-A699-4EF3-9A70-130B92154B11";
NSRange range1 = [testString1 rangeOfString:reString options:NSRegularExpressionSearch];
NSLog(#"testString1: %#", (range1.location != NSNotFound && range1.length == testString1.length) ? #"Good" : #"Bad");
NSString *testString2 = #"zDD2B9F7-A699-4EF3-9A70-130B92154B11";
NSRange range2 = [testString2 rangeOfString:reString options:NSRegularExpressionSearch];
NSLog(#"testString2: %#", (range1.location != NSNotFound && range2.length == testString2.length) ? #"Good" : #"Bad");
For a more rigorous GUID match:
NSString *reString = #"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";

NSString value validation in iOS

This simple validation method for NSString makes trouble.
I have an NSString value and I want to validate the string, i.e, if the string contains only 'a to z' (or) 'A to Z' (or) '1 to 9' (or) '#,!,&' then the string is valid. If the string contains any other values then this the NSString is invalid, how can i validate this..?
As example:
Valid:
NSString *str="aHrt#2"; // something like this
Invalid:
NSString *str="..gS$"; // Like this
Try using character sets:
NSMutableCharacterSet *set = [NSMutableCharacterSet characterSetWithCharactersInString:#"#!&"];
[set formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]];
if ([string rangeOfCharacterFromSet:[set invertedSet]].location == NSNotFound) {
// contains a-z, A-Z, 0-9 and &#! only - valid
} else {
// invalid
}
I would do something using stringByTrimmingCharactersInSet
Create an NSCharacterSet containing all valid characters, then trim those characters from the test string, if the string is now empty it is valid, if there are any characters left over, it is invalid
NSCharacterSet *validCharacters = [NSCharacterSet characterSetWithCharactersInString:#"myvalidchars"];
NSString *trimmedString = [testString stringByTrimmingCharactersInSet:validCharachters];
BOOL valid = [trimmedString length] == 0;
Edit:
If you want to control the characters that can be entered into a text field, use textField:shouldChangeCharactersInRange:replacementString: in UITextFieldDelegate
here the testString variable becomes the proposed string and you return YES if there are no invalid characters
The NSPredicate class is what you want
More info about predicate programming. Basically you want "self matches" (your regular expression). After that you can use the evaluateWithObject: method.
EDIT Easier way: (nevermind, as I am editing it wattson posted what I was going to)
You can use the class NSRegularExpression to do this.
https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html
You can also use NSRegularExpression to search your NSString, if it contains only the valid characters (or vice versa).
More info:
Search through NSString using Regular Expression
Use regular expression to find/replace substring in NSString
- (BOOL)validation:(NSString *)string
{
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:#"1234567890abcdefghik"] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return ([string isEqualToString:filtered]);
}
In your button action:
-(IBAction)ButtonPress{
if ([self validation:activity.text]) {
NSLog(#"Macth here");
}
else {
NSLog(#"Not Match here");
}
}
Replace this "1234567890abcdefghik" with your letters with which you want to match
+(BOOL) validateString: (NSString *) string
{
NSString *regex = #"[A-Z0-9a-z#!&]";
NSPredicate *test = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];
BOOL isValid = [test evaluateWithObject:string];
return isValid;
}
You can simply do it using NSMutableCharacterSet
NSMutableCharacterSet *charactersToKeep = [NSMutableCharacterSet alphanumericCharacterSet];
[charactersToKeep addCharactersInString:#"#?!"];
NSCharacterSet *charactersToRemove = [charactersToKeep invertedSet]
NSString *trimmed = [ str componentsSeparatedByCharactersInSet:charactersToRemove];
if([trimmed length] != 0)
{
//invalid string
}
Reference NSCharacterSet
You can use regex. If every thing fails use brute force like
unichar c[yourString.length];
NSRange raneg={0,2};
[yourString getCharacters:c range:raneg];
// now in for loop
for(int i=0;i<yourString.length;i++)
{
if((c[i]>='A'&&c[i]<='Z')&&(c[i]=='#'||c[i]=='!'||c[i]=='&'))
{
//not the best or most efficient way but will work till you write your regex:P
}
}

NSTextCheckingResult for phone numbers

Can someone tell me why this evaluates every time to true?!
The input is: jkhkjhkj. It doesn't matter what I type into the phone field. It's every time true...
NSRange range = NSMakeRange (0, [phone length]);
NSTextCheckingResult *match = [NSTextCheckingResult phoneNumberCheckingResultWithRange:range phoneNumber:phone];
if ([match resultType] == NSTextCheckingTypePhoneNumber)
{
return YES;
}
else
{
return NO;
}
Here is the value of match:
(NSTextCheckingResult *) $4 = 0x0ab3ba30 <NSPhoneNumberCheckingResult: 0xab3ba30>{0, 8}{jkhkjhkj}
I was using RegEx and NSPredicate but I've read that since iOS4 it's recommended to use NSTextCheckingResult but I can't find any good tutorials or examples on this.
Thanks in advance!
You are using the class incorrectly. NSTextCheckingResult is the result of a text checking that is done by NSDataDetector or NSRegularExpression. Use NSDataDetector instead:
NSError *error = NULL;
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber error:&error];
NSRange inputRange = NSMakeRange(0, [phone length]);
NSArray *matches = [detector matchesInString:phone options:0 range:inputRange];
// no match at all
if ([matches count] == 0) {
return NO;
}
// found match but we need to check if it matched the whole string
NSTextCheckingResult *result = (NSTextCheckingResult *)[matches objectAtIndex:0];
if ([result resultType] == NSTextCheckingTypePhoneNumber && result.range.location == inputRange.location && result.range.length == inputRange.length) {
// it matched the whole string
return YES;
}
else {
// it only matched partial string
return NO;
}

Get filename from Content-Disposition header

I'm currently checking for this header and if it's available, I'll try to get the filename from it. Question is, what is the best method to retrieve it? I understand that Content-Disposition header may appear with different parameters. Examples below:
Content-Disposition = "inline; filename=sample-file-123.pdf"
Content-Disposition = "attachment; filename="123.zip""
I'm only interested to get the filename.
There is a dedicated API for this: URLResponse.suggestedFilename
So if you are getting your header from a URLResponse you just call
let filename: String = response.suggestedFilename ?? "default"
and you're done. Note that despite what the documentation says, the return value is optional so you have to provide a default or force unwrap if you dare (I wouldn't).
From the documentation:
The method first checks if the server has specified a filename using the
content disposition header. If no valid filename is specified using that mechanism,
this method checks the last path component of the URL. If no valid filename can be
obtained using the last path component, this method uses the URL's host as the filename.
If the URL's host can't be converted to a valid filename, the filename "unknown" is used.
In mose cases, this method appends the proper file extension based on the MIME type.
This method always returns a valid filename.
I would do something along the lines of this:
- (NSString *)getFilenameFrom:(NSString *)string {
NSRange startRange = [string rangeOfString:#"filename="];
if (startRange.location != NSNotFound && startRange.length != NSNotFound) {
int filenameStart = startRange.location + startRange.length;
NSRange endRange = [string rangeOfString:#" " options:NSLiteralSearch range:NSMakeRange(filenameStart, [string length] - filenameStart)];
int filenameLength = 0;
if (endRange.location != NSNotFound && endRange.length != NSNotFound) {
filenameLength = endRange.location - filenameStart;
} else {
filenameLength = [string length] - filenameStart;
}
return [string substringWithRange:NSMakeRange(filenameStart, filenameLength)];
}
return nil; //or return #"", whatever you like
}
You will have to check it as i made this in the browser (dont have access to xcode atm).
+ (NSString *)filenameFromContentDispositionHeader:(NSString *)contentDispositionHeader {
NSString *pattern = #"filename=\"(.*)\"";
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
NSTextCheckingResult *result =
[regex firstMatchInString:contentDispositionHeader
options:0
range:NSMakeRange(0, contentDispositionHeader.length)];
NSRange resultRange = [result rangeAtIndex:0];
if (resultRange.location == NSNotFound) {
return nil;
} else {
return [contentDispositionHeader substringWithRange:
NSMakeRange(resultRange.location + 10, resultRange.length - 11)];
}
}
Note that you'll need to modify the pattern if you can't be sure the filename is surrounded in double-quotes.

iPhone 'Whole Word' Search

I am currently using the following algorithm to search on my iPhone app:
NSRange range = [entry.englishEntry rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(range.location != NSNotFound)
{
[self.filteredListContent addObject:entry];
}
The problem is that when I search for a word like 'crap' I also get results for words like 'scrap' which is irrelevant. I am unfamiliar with NSRange so what is the search algorithm for searching the whole word?
I just solved this problem by adding a simple category on NSString to do a word boundary search. Here's the code:
#interface NSString (FullWordSearch)
// Search for a complete word. Does not match substrings of words. Requires fullWord be present
// and no surrounding alphanumeric characters.
- (BOOL)containsFullWord:(NSString *)fullWord;
#end
#implementation NSString (FullWordSearch)
- (BOOL)containsFullWord:(NSString *)fullWord {
NSRange result = [self rangeOfString:fullWord];
if (result.length > 0) {
if (result.location > 0 && [[NSCharacterSet alphanumericCharacterSet] characterIsMember:[self characterAtIndex:result.location - 1]]) {
// Preceding character is alphanumeric
return NO;
}
if (result.location + result.length < [self length] && [[NSCharacterSet alphanumericCharacterSet] characterIsMember:[self characterAtIndex:result.location + result.length]]) {
// Trailing character is alphanumeric
return NO;
}
return YES;
}
return NO;
}
#end
Yes you can search within words. You need to split the string into components first. Then loop through each one and compare them.
Something like that:
NSArray *words = [entry.english componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
for (NSString *word in words)
{
NSComparisonResult result = [word compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame)
{
[self.filteredListContent addObject:entry];
break;
}
}
Instead of finding the range of a string, just do a case-insensitive compare and check if the result is NSOrderedSame
if([entry.english caseInsensitiveCompare:searchText] == NSOrderedSame){
[self.filteredListContent addObject:entry];
}
This will compare the text with the whole word and not just look for the range.
Now i make it as more generic, by using this code you can search any string between target string
NSString * strName =[entry.english lowercaseString];
if ([strName rangeOfString:[searchText lowercaseString]].location != NSNotFound) {
[self.filteredListContent addObject:entry];}