ios8 to validate urlField? [duplicate] - ios

Help me to write the code like "if my string is a valid URL do smth"
Is it possible to write this in a couple strings of code?

I will assume that by URL, you are referring to a string identifying a internet resource location.
If you have an idea about the format of the input string , then why not manually check if the string starts with http://, https:// or any other scheme you need. If you expect other protocols, you can also add them to the check list (e.g. ftp://, mailto://, etc)
if ([myString hasPrefix:#"http://"] || [myString hasPrefix:#"https://"])
{
// do something
}
If you are looking for a more solid solution and detect any kind of URL scheme, then you should use a regular expression.
As a side note, the NSURL class is designed to express any kind of resource location (not just internet resources). That is why, strings like img/demo.jpg or file://bla/bla/bla/demo.jpg can be transformed into NSURL objects.
However, according to the documentation the [NSURL URLWithString] should return nil if the input string is not a valid internet resource string. In practice it doesn't.

+ (BOOL)validateUrlString:(NSString*)urlString
{
if (!urlString)
{
return NO;
}
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSRange urlStringRange = NSMakeRange(0, [urlString length]);
NSMatchingOptions matchingOptions = 0;
if (1 != [linkDetector numberOfMatchesInString:urlString options:matchingOptions range:urlStringRange])
{
return NO;
}
NSTextCheckingResult *checkingResult = [linkDetector firstMatchInString:urlString options:matchingOptions range:urlStringRange];
return checkingResult.resultType == NSTextCheckingTypeLink
&& NSEqualRanges(checkingResult.range, urlStringRange);
}

I used this solution which is apparently a better and less complex check than a Regex check -
- (BOOL)isURL:(NSString *)inputString
{
NSURL *candidateURL = [NSURL URLWithString:inputString];
return candidateURL && candidateURL.scheme && candidateURL.host;
}

Try to create NSUrl with it, and see if it returns non-nil result.

if ([NSURL URLWithString:text]) {
// valid URL
}
else {
// invalid URL
}

Related

A clean and robust way to parse URL strings in Objective C

I have a requirement to take a string that represents a URL that can be in many formats and standardise it so it conforms with the URL spec.
If the URL string does not have a scheme, or it has a scheme that is not 'http' or 'https', it should use a default scheme.
I wanted to use NSURLComponents but if a scheme is not provided it parses the host as a path
NSURLComponents *components = [NSURLComponents componentsWithString:#"www.google.com.au"];
components.scheme = #"http";
NSLog(#"1: %#", components.path);
NSLog(#"2: %#", components.host);
NSLog(#"3: %#", components.string);
testtest[2619:869020] 1: www.google.com.au
testtest[2619:869020] 2: ((null))
testtest[2619:869020] 3: http:www.google.com.au <-- Invalid
Therefore I ended up with this category on NSString
#define DEFAULT_SCHEME #"http"
#implementation NSString (standardiseUrlFormat)
- (NSString*)standardiseUrlFormat {
NSURLComponents *components = [NSURLComponents componentsWithString:self];
BOOL hasScheme = components.scheme != nil;
// If no scheme or an invalid scheme is provided, default to http
if (!hasScheme) {
// We have to use string concatenation here because NSURLComponents will
// put the hostname as the path if there is no scheme
return [NSString stringWithFormat:#"%#://%#", DEFAULT_SCHEME, self];
}
// Now we know that a scheme exists, check if it is a correct scheme
if (![components.scheme isEqualToString:#"http"] &&
![components.scheme isEqualToString:#"https"]) {
// Overwrite scheme if not supported
components.scheme = DEFAULT_SCHEME;
}
return [components string];
}
#end
With the following output
NSLog(#"1: %#", [#"http://www.google.com" standardiseUrlFormat]);
NSLog(#"2: %#", [#"www.google.com" standardiseUrlFormat]);
NSLog(#"3: %#", [#"https://www.google.com" standardiseUrlFormat]);
NSLog(#"4: %#", [#"https://www.google.com/some_path" standardiseUrlFormat]);
NSLog(#"5: %#", [#"www.google.com/some_path" standardiseUrlFormat]);
testtest[7411:944022] 1: http://www.google.com
testtest[7411:944022] 2: http://www.google.com
testtest[7411:944022] 3: https://www.google.com
testtest[7411:944022] 4: https://www.google.com/some_path
testtest[7411:944022] 5: http://www.google.com/some_path
Can anyone suggest a cleaner solution that doesn't use two methods (NSURLComponents and string concatenation) to construct the string?
Don't use string concatenation at all. Use NSURLComponents to form the desired NSURL; that's what it's for. For example, if you don't like what the scheme is, set the scheme to what you do want.
EDIT I guess I was thinking that having detected that this is a hostless URL you would rejigger it by hand, e.g.
let s = "www.apple.com/whatever" as NSString
let arr = s.pathComponents
let c = NSURLComponents()
c.scheme = "http"
c.host = arr[0]
c.path = "/" + (Array(arr.dropFirst()) as NSArray).componentsJoinedByString("/")
But perhaps this can't be done, and the problem really is that a URL without a scheme is more or less not a URL.

Get position of NSString in string - iOS

I am developing an iOS app and one of the things I need to do it to go over URLs and replace the first protocol section with my own custom protocol.
How can I delete the first few characters of a NSString before the "://"?
So for example I need convert the following:
http://website.com --> cstp://website.com
ftp://website.com --> oftp://website.com
https://website.com --> ctcps://website.com
The main problem I face, is that I can't just delete the first 'x' number of characters from the URL string. I have to detect how many characters there are till the "://" characters are reached.
So how can I count how many characters there are from that start of the string to the "://" characters?
Once I know this, I can then simply do the following to delete the characters:
int counter = ... number of characters ...
NSString *newAddress = [webURL substringFromIndex:counter];
Thanks for your time, Dan.
http://website.com is a URL, and http is the scheme part of the URL. Instead of string manipulation I would recommend to use the
NSURLComponents class which is made exactly for this purpose: inspect, create and modify URLs:
NSString *originalURL = #"http://website.com";
NSURLComponents *urlcomp = [[NSURLComponents alloc] initWithString:originalURL];
if ([urlcomp.scheme isEqualToString:#"http"]) {
urlcomp.scheme = #"cstp";
} else if ([urlcomp.scheme isEqualToString:#"ftp"]) {
urlcomp.scheme = #"otfp";
}
// ... handle remaining cases ...
NSString *modifiedURL = [urlcomp string];
NSLog(#"%#", modifiedURL); // cstp://website.com
If the number of cases grows then a dictionary mapping is easier to
manage:
NSDictionary *schemesMapping = #{
#"http" : #"cstp",
#"ftp" : #"otfp"
#"https" : #"ctcps" };
NSURLComponents *urlcomp = [[NSURLComponents alloc] initWithString:originalURL];
NSString *newScheme = schemesMapping[urlcomp.scheme];
if (newScheme != nil) {
urlcomp.scheme = newScheme;
}
NSString *modifiedURL = [urlcomp string];
You can use:
NSRange range = [urlString rangeOfString:#"://"];
range.location will give you the first index from where the "://" starts and you can use it as:
NSString *newAddress = [urlString substringFromIndex:range.location];
and append your prefix:
NSString *finalAddress = [NSString stringWithFormat:#"%#%#", prefixString, newAddress];

Parsing strings: String before character

Input:
chris#mydomain.com
steve#mydomain.com
Output:
chris
steve
I'm looking to get the substring before the # character. In Python, I would use something like: myString = myString[:myString.find("#")] but I think Swift's version is very complex, at least from what I've been reading. Would it be better to bridge to Obj-C in this case, since Swift's indexOf/find function looks something like this mess: Finding index of character in Swift String ?
Something like this, even though it's using arrays, seems to be the simpliest route:
contact = contact.componentsSeparatedByString("#")[0]
In Swift, Python myString[:myString.find("#")] is equivalent to:
myString[myString.startIndex ..< find(myString, "#")!]
But this causes a runtime error unless myString contains "#".
This is safer.
if let found = find(myString, "#") {
myString = myString[myString.startIndex ..< found]
}
Note that, find() searches Character only, not substring. so you cannot:
find(myString, "#mydomain")
This may help you
let arr = split(contact, { $0 == "#"}, maxSplit: Int.max, allowEmptySlices: false)
println(arr[0])
I believe you have hit the nail on the head. Another option is to use regular expressions to find it. I'm still learning swift, but the objective-c version of things is as follows:
-(NSString*) parseEmailPrefix(NSString*)email{
NSError *error = nil;
NSString *pattern = #"([A-Z0-9a-z._%+-]+)#[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern
options:0
error:&error];
NSTextCheckingResult *result = [expression firstMatchInString:email
options:0
range:NSMakeRange(0, email.length)];
return [string substringWithRange:[result rangeAtIndex:1]];
}
This is in my opinion harder to read, but it has the added benefit of validating the email as you go.
Regex credit: Regex for email address
And then there is this Obj-C snippet, which addresses more specifically the data given in the question. (Forgive that I have not translated to Swift, still working on that skill.)
NSString* email = #"chuck#norris.net";
NSURL* theURL = [NSURL URLWithString:[NSString stringWithFormat:#"mailto://%#", email]];
NSLog(#"%# at %#", theURL.user, theURL.host); // yields "chuck at norris.net"
This works:
var str: String = "Hello#World"
let a = str.componentsSeparatedByString("#")
println("\(a[0])")
Output is "Hello"

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.

NSString find and replace html tags attgibutes

I have pretty simple NSString
f.e
<scirpt attribute_1="x" attribute2="x" attribute3="x" ... attributeX="x"/>
I need to find specific parameter, let's say attribute2 and replace it's value,
I know the exact name of parameter f.e attribute2 but I don't know anything about it's value.
I guess it can be easily done by regexp, but I quite newbie on it.
In conclusion: I want to grab
attribute2="xxxx...xxx"
from incoming string
Note: I don't want to use some 3rd party libs to achieve that (it's temporary hack)
Any help is appreciated
I hacked it together with some string operations:
NSDictionary* valuesToReplace = #{#"attribute_1" : #"newValue1"};
NSString* sourceHtml = #"<scirpt attribute_1=\"x\" attribute2=\"x\" attribute3=\"x\" attributeX=\"x\" />";
NSArray* attributes = [sourceHtml componentsSeparatedByString:#" "];
for (NSString* pair in attributes)
{
NSArray* attributeValue = [pair componentsSeparatedByString:#"="];
if([attributeValue count] > 1) //to skip first "script" element
{
NSString* attr = [attributeValue firstObject]; //get attribute name
if([valuesToReplace objectForKey:attr]) //check if should be replaced
{
NSString* newPair = [NSString stringWithFormat:#"%#=\"%#\"", attr, [valuesToReplace objectForKey:attr]]; //create new string for that attribute
sourceHtml = [sourceHtml stringByReplacingOccurrencesOfString:pair withString:newPair]; //replace it in sourceHtml
}
}
}
It's really only when you want to hack it and you know the format :) Shoot a question if you have any.
you can try this.. https://github.com/mwaterfall/MWFeedParser
import "NSString+HTML.h" along with dependencies
And write like this...
simpletxt.text = [YourHTMLString stringByConvertingHTMLToPlainText];

Resources