Check email with NSDataDetector - iphone

I have a string coming from server and want to check whether it contains expressions like phone numbers, mail address and email. I got success in case of phone number and mail address, but not email. I am using NSDataDetector for this purpose. eg
NSString *string = sourceNode.label; //coming from server
//Phone number
NSDataDetector *phoneDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber error:nil];
NSArray *phoneMatches = [phoneDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in phoneMatches) {
if ([match resultType] == NSTextCheckingTypePhoneNumber) {
NSString *matchingStringPhone = [match description];
NSLog(#"found URL: %#", matchingStringPhone);
}
}
But how to do the same for email?

if (result.resultType == NSTextCheckingTypeLink)
{
if ([result.URL.scheme.locaseString isEqualToString:#"mailto"])
{
// email link
}
else
{
// url
}
}
Email address falls into NSTextCheckingTypeLink. Simply look for "mailto:" in the URL found and you will know it is an email or URL.

EDIT:
my answer has been accepted in 2012 and is pretty outdated. Please read please this one instead.
Original post:
In apple documentation, it seems that recognised types does not include email :
http://developer.apple.com/library/IOs/#documentation/AppKit/Reference/NSTextCheckingResult_Class/Reference/Reference.html#//apple_ref/c/tdef/NSTextCheckingType
So I suggest you to use a Regexp.
It would be like :
NSString* pattern = #"[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]+";
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pattern];
if ([predicate evaluateWithObject:#"johndoe#example.com"] == YES) {
// Okay
} else {
// Not found
}

Try following code, see if it works for you :
NSString * mail = so#so.com
NSDataDetector * dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSTextCheckingResult * firstMatch = [dataDetector firstMatchInString:mail options:0 range:NSMakeRange(0, [mail length])];
BOOL result = [firstMatch.URL isKindOfClass:[NSURL class]] && [firstMatch.URL.scheme isEqualToString:#"mailto"];

Here's a clean Swift version.
extension String {
func isValidEmail() -> Bool {
guard !self.lowercaseString.hasPrefix("mailto:") else { return false }
guard let emailDetector = try? NSDataDetector(types: NSTextCheckingType.Link.rawValue) else { return false }
let matches = emailDetector.matchesInString(self, options: NSMatchingOptions.Anchored, range: NSRange(location: 0, length: self.characters.count))
guard matches.count == 1 else { return false }
return matches[0].URL?.absoluteString == "mailto:\(self)"
}
}
Swift 3.0 Version:
extension String {
func isValidEmail() -> Bool {
guard !self.lowercased().hasPrefix("mailto:") else { return false }
guard let emailDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else { return false }
let matches = emailDetector.matches(in: self, options: NSRegularExpression.MatchingOptions.anchored, range: NSRange(location: 0, length: self.characters.count))
guard matches.count == 1 else { return false }
return matches[0].url?.absoluteString == "mailto:\(self)"
}
}
Objective-C:
#implementation NSString (EmailValidator)
- (BOOL)isValidEmail {
if ([self.lowercaseString hasPrefix:#"mailto:"]) { return NO; }
NSDataDetector* dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
if (dataDetector == nil) { return NO; }
NSArray* matches = [dataDetector matchesInString:self options:NSMatchingAnchored range:NSMakeRange(0, [self length])];
if (matches.count != 1) { return NO; }
NSTextCheckingResult* match = [matches firstObject];
return match.resultType == NSTextCheckingTypeLink && [match.URL.absoluteString isEqualToString:[NSString stringWithFormat:#"mailto:%#", self]];
}
#end

Here's an up to date playground compatible version that builds on top of Dave Wood's and mkto's answer:
import Foundation
func isValid(email: String) -> Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let range = NSRange(location: 0, length: email.count)
let matches = detector.matches(in: email, options: .anchored, range: range)
guard matches.count == 1 else { return false }
return matches[0].url?.scheme == "mailto"
} catch {
return false
}
}
extension String {
var isValidEmail: Bool {
isValid(email: self)
}
}
let email = "test#mail.com"
isValid(email: email) // prints 'true'
email.isValidEmail // prints 'true'

It seems detector now works for email?
let types = [NSTextCheckingType.Link, NSTextCheckingType.PhoneNumber] as NSTextCheckingType
responseAttributedLabel.enabledTextCheckingTypes = types.rawValue
And I am able to click on emails. I am using the TTTAttributedLabel though.

Here's an email example in Swift 1.2. Might not check all edge cases, but it's a good place to start.
func isEmail(emailString : String)->Bool {
// need optional - will be nil if successful
var error : NSError?
// use countElements() with Swift 1.1
var textRange = NSMakeRange(0, count(emailString))
// Link type includes email (mailto)
var detector : NSDataDetector = NSDataDetector(types: NSTextCheckingType.Link.rawValue, error: &error)!
if error == nil {
// options value is ignored for this method, but still required!
var result = detector.firstMatchInString(emailString, options: NSMatchingOptions.Anchored, range: textRange)
if result != nil {
// check range to make sure a substring was not detected
return result!.URL!.scheme! == "mailto" && (result!.range.location == textRange.location) && (result!.range.length == textRange.length)
}
} else {
// handle error
}
return false
}
let validEmail = isEmail("someone#site.com") // returns true

Related

I want to check the validation for both mobile number and email id in single textfield. How should I validate this?

I want to check the validation for both "Email id " and "mobile number" in single textfield. How should I validate the conditions for the same textfield?
Maybe this will help:
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSMakeRange(0, self.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.count
} else {
return false
}
} catch {
return false
}
}
}
extension String {
var isInt: Bool {
return Int(self) != nil
}
}
func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: testStr)
}
if textField.text.characterCount > 6 {
if textField.text.isInt == true {
print("this might be users phone number"
} else if isValidEmail(testStr:textField.text) {
print("this might be users mail")
} else {
print("user entered wrong value or nothing")
}

Play audio if headset is plugged-in [duplicate]

Is it possible to detect that the user has an external headset plugged into the iPhone's 3.5mm connector or the 30-pin connector? I want to output audio only to an external audio device, and keep silent if nothing is connected.
The answer is very similar to the answer to this question, but you'll want to get the kAudioSessionProperty_AudioRoute property instead.
Call this method to find out the bluetooth headset is connected or not.
First import this framework #import <AVFoundation/AVFoundation.h>
- (BOOL) isBluetoothHeadsetConnected
{
AVAudioSession *session = [AVAudioSession sharedInstance];
AVAudioSessionRouteDescription *routeDescription = [session currentRoute];
NSLog(#"Current Routes : %#", routeDescription);
if (routeDescription)
{
NSArray *outputs = [routeDescription outputs];
if (outputs && [outputs count] > 0)
{
AVAudioSessionPortDescription *portDescription = [outputs objectAtIndex:0];
NSString *portType = [portDescription portType];
NSLog(#"dataSourceName : %#", portType);
if (portType && [portType isEqualToString:#"BluetoothA2DPOutput"])
{
return YES;
}
}
}
return NO;
}
There is nice article about this in Apple documentation:
https://developer.apple.com/documentation/avfoundation/avaudiosession/responding_to_audio_session_route_changes
Only you have to verify if portType == AVAudioSessionPortBluetoothA2DP
func setupNotifications() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(handleRouteChange),
name: .AVAudioSessionRouteChange,
object: nil)
}
#objc func handleRouteChange(notification: Notification) {
guard let userInfo = notification.userInfo,
let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
return
}
switch reason {
case .newDeviceAvailable:
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = true
break
}
case .oldDeviceUnavailable:
if let previousRoute =
userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
for output in previousRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = false
break
}
}
default: ()
}
}
func isBluetoothHeadsetConnected() -> Bool {
var result = false
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
result = true
}
return result
}

NSString and NSDictionary valueForKey - nil?

How can I put a default value into my string if getting data from an empty key/value in a dictionary.
so [myObject setMyString:[dictionary valueForKey:#"myKey"]];
So then if I did NSString *newString = myObject.myString I would get an unrecognized selector error.
So again, I simply need a way to insert a default string if the key value is empty;
If dictionary is a NSDictionary you should probably use objectForKey as valueForKey is used for KVC. It works for NSDictionary but may bite you if the key collide with some NSDictionary KVC key, e.g. "#allKeys" or "#count".
I think the shortest is probably to do:
[dictionary objectForkey:#"myKey"] ?: #"defaultValue"
There is one terrible way of abusing the existing dictionary methods to produce a get by key or return a default value if you don't want to use a condition for some reason...
[[dictionary objectsForKeys:[NSArray arrayWithObject:#"myKey"]
notFoundMarker:#"defaultValue"]
objectAtIndex:0]
You did not hear it from me :)
What about this?
NSString *value = [dictionary valueForKey:#"myKey"];
if (!value) value = #"defaultValue";
[myObject setMyString:value];
Use [NSNull null] for the general case, and handle it when that is returned.
In your question, you wouldn't get "unrecognised selector"; newString would be set to nil (as opposed to [NSNull null], so I suspect you might have meant something else - perhaps how to set defaults values for NSUserDefaults?
I've done this with a simple NSDictionary extension.
NSDictionary+NSDictionaryExtensions.h
#import <Foundation/Foundation.h>
#interface NSDictionary (NSDictionaryExtensions)
- (id)objectForKey:(id)aKey defaultObject: (id) defObj;
#end
NSDictionary+NSDictionaryExtensions.m
#import "NSDictionary+NSDictionaryExtensions.h"
#implementation NSDictionary (NSDictionaryExtensions)
- (id)objectForKey:(id)aKey defaultObject: (id) defObj
{
id ret = [self objectForKey: aKey];
if ( ret == nil )
return defObj;
else
return ret;
}
#end
I can then access as follows:
NSString* str = [dict objectForKey: #"a_key" defaultObject: #"default"];
try
if ( myObject == nil ) {
[myObject setMyString:#""];
}
or
if ( [dictionary valueForKey:#"myKey"] == nil ) {
[dictionary setObject:#"" forKey:#"myKey"];
}
Whatever default value you assigned to your string it will not make myObject.myString return "unrecognized selector error" - usually the property myString either exists or it does not ('usually' as you can dig into the guts of the Objective-C runtime and play games, but this is rarely (if ever) what you want to do!)
What are you trying to do? If your aim is to throw an exception on myObject.myString not being set then you can do that in the property implementation.
For example, valueForKey; will return nil if there is no value set for a given key, so you can check for that in your property:
- (void) setMyString:(NSString *)value
{ myString = value;
}
- (NSString *) myString
{
if (myString == nil)
#throw [NSException exceptionWithName:#"UnrecognizedSelector" reason:#"No value set for myString" userInfo:nil];
return myString;
}
Notes:
code typed at terminal, may contain typos
code assumes garbage collection/ARC on, if not you need to add appropriate retain/copy/release
But do you really want to throw an exception? You would normally only do so if the string should be set and not being so is an exceptional condition - you don't throw for default values.
As per #Paul Lynch you must check for [NSNull null] apart from nil. It is also advisable to check for the data type you are looking for:
- (id) objectForKey: (id) key withDefault: (id) defaultValue
{
id value = self[key];
if (value == nil || [value isEqual: [NSNull null]] || ![defaultValue isKindOfClass: [value class]])
{
value = defaultValue;
}
return value;
}
You can manually check for nil values as below for different types:
extension NSDictionary {
func convertToString() -> String {
let jsonData = try! JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted) as NSData!
if jsonData == nil{
return "{}"
}else {
return String(data: jsonData as! Data, encoding: String.Encoding.utf8)!
}
}
func object_forKeyWithValidationForClass_Int(aKey: String) -> Int {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return Int()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return Int()
}
} else {
// KEY NOT FOUND
return Int()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return Int()
}
else if(aValue.isKind(of: NSString.self)){
return Int((aValue as! NSString).intValue)
}
else {
if aValue is Int {
return self.object(forKey: aKey) as! Int
}
else{
return Int()
}
}
}
func object_forKeyWithValidationForClass_CGFloat(aKey: String) -> CGFloat {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return CGFloat()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return CGFloat()
}
} else {
// KEY NOT FOUND
return CGFloat()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return CGFloat()
}
else {
if aValue is CGFloat {
return self.object(forKey: aKey) as! CGFloat
}
else{
return CGFloat()
}
}
}
func object_forKeyWithValidationForClass_String(aKey: String) -> String {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return String()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return String()
}
} else {
// KEY NOT FOUND
return String()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return String()
}
else if(aValue.isKind(of: NSNumber.self)){
return String(format:"%f", (aValue as! NSNumber).doubleValue)
}
else {
if aValue is String {
return self.object(forKey: aKey) as! String
}
else{
return String()
}
}
}
func object_forKeyWithValidationForClass_StringInt(aKey: String) -> String {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return String()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return String()
}
} else {
// KEY NOT FOUND
return String()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return String()
}
else if(aValue.isKind(of: NSNumber.self)){
return String(format:"%d", (aValue as! NSNumber).int64Value)
}
else {
if aValue is String {
return self.object(forKey: aKey) as! String
}
else{
return String()
}
}
}
func object_forKeyWithValidationForClass_Bool(aKey: String) -> Bool {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return Bool()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return Bool()
}
} else {
// KEY NOT FOUND
return Bool()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return Bool()
}
else {
if aValue is Bool {
return self.object(forKey: aKey) as! Bool
}
else{
return Bool()
}
}
}
func object_forKeyWithValidationForClass_NSArray(aKey: String) -> NSArray {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSArray()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSArray()
}
} else {
// KEY NOT FOUND
return NSArray()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSArray()
}
else {
if aValue is NSArray {
return self.object(forKey: aKey) as! NSArray
}
else{
return NSArray()
}
}
}
func object_forKeyWithValidationForClass_NSMutableArray(aKey: String) -> NSMutableArray {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSMutableArray()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSMutableArray()
}
} else {
// KEY NOT FOUND
return NSMutableArray()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSMutableArray()
}
else {
if aValue is NSMutableArray {
return self.object(forKey: aKey) as! NSMutableArray
}
else{
return NSMutableArray()
}
}
}
func object_forKeyWithValidationForClass_NSDictionary(aKey: String) -> NSDictionary {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSDictionary()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSDictionary()
}
} else {
// KEY NOT FOUND
return NSDictionary()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSDictionary()
}
else {
if aValue is NSDictionary {
return self.object(forKey: aKey) as! NSDictionary
}
else{
return NSDictionary()
}
}
}
func object_forKeyWithValidationForClass_NSMutableDictionary(aKey: String) -> NSMutableDictionary {
// CHECK FOR EMPTY
if(self.allKeys.count == 0) {
return NSMutableDictionary()
}
// CHECK IF KEY EXIST
if let val = self.object(forKey: aKey) {
if((val as AnyObject).isEqual(NSNull())) {
return NSMutableDictionary()
}
} else {
// KEY NOT FOUND
return NSMutableDictionary()
}
// CHECK FOR NIL VALUE
let aValue : AnyObject = self.object(forKey: aKey)! as AnyObject
if aValue.isEqual(NSNull()) {
return NSMutableDictionary()
}
else {
if aValue is NSMutableDictionary {
return self.object(forKey: aKey) as! NSMutableDictionary
}
else{
return NSMutableDictionary()
}
}
}
}

How to validate a website name in UItextfield in objective c? [duplicate]

In an iPhone app I am developing, there is a setting in which you can enter a URL, because of form & function this URL needs to be validated online as well as offline.
So far I haven't been able to find any method to validate the url, so the question is;
How do I validate an URL input on the iPhone (Objective-C) online as well as offline?
Why not instead simply rely on Foundation.framework?
That does the job and does not require RegexKit :
NSURL *candidateURL = [NSURL URLWithString:candidate];
// WARNING > "test" is an URL according to RFCs, being just a path
// so you still should check scheme and all other NSURL attributes you need
if (candidateURL && candidateURL.scheme && candidateURL.host) {
// candidate is a well-formed url with:
// - a scheme (like http://)
// - a host (like stackoverflow.com)
}
According to Apple documentation :
URLWithString: Creates and returns an NSURL object initialized with a
provided string.
+ (id)URLWithString:(NSString *)URLString
Parameters
URLString : The string with which to initialize the NSURL object. Must conform to RFC 2396. This method parses URLString according to RFCs 1738 and 1808.
Return Value
An NSURL object initialized with URLString. If the string was malformed, returns nil.
Thanks to this post, you can avoid using RegexKit.
Here is my solution (works for iphone development with iOS > 3.0) :
- (BOOL) validateUrl: (NSString *) candidate {
NSString *urlRegEx =
#"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
NSPredicate *urlTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", urlRegEx];
return [urlTest evaluateWithObject:candidate];
}
If you want to check in Swift my solution given below:
func isValidUrl(url: String) -> Bool {
let urlRegEx = "^(https?://)?(www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6}(/[-\\w#\\+\\.~#\\?&/=%]*)?$"
let urlTest = NSPredicate(format:"SELF MATCHES %#", urlRegEx)
let result = urlTest.evaluate(with: url)
return result
}
Instead of writing your own regular expressions, rely on Apple's. I have been using a category on NSString that uses NSDataDetector to test for the presence of a link within a string. If the range of the link found by NSDataDetector equals the length of the entire string, then it is a valid URL.
- (BOOL)isValidURL {
NSUInteger length = [self length];
// Empty strings should return NO
if (length > 0) {
NSError *error = nil;
NSDataDetector *dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
if (dataDetector && !error) {
NSRange range = NSMakeRange(0, length);
NSRange notFoundRange = (NSRange){NSNotFound, 0};
NSRange linkRange = [dataDetector rangeOfFirstMatchInString:self options:0 range:range];
if (!NSEqualRanges(notFoundRange, linkRange) && NSEqualRanges(range, linkRange)) {
return YES;
}
}
else {
NSLog(#"Could not create link data detector: %# %#", [error localizedDescription], [error userInfo]);
}
}
return NO;
}
My solution with Swift:
func validateUrl (stringURL : NSString) -> Bool {
var urlRegEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
let predicate = NSPredicate(format:"SELF MATCHES %#", argumentArray:[urlRegEx])
var urlTest = NSPredicate.predicateWithSubstitutionVariables(predicate)
return predicate.evaluateWithObject(stringURL)
}
For Test:
var boolean1 = validateUrl("http.s://www.gmail.com")
var boolean2 = validateUrl("https:.//gmailcom")
var boolean3 = validateUrl("https://gmail.me.")
var boolean4 = validateUrl("https://www.gmail.me.com.com.com.com")
var boolean6 = validateUrl("http:/./ww-w.wowone.com")
var boolean7 = validateUrl("http://.www.wowone")
var boolean8 = validateUrl("http://www.wow-one.com")
var boolean9 = validateUrl("http://www.wow_one.com")
var boolean10 = validateUrl("http://.")
var boolean11 = validateUrl("http://")
var boolean12 = validateUrl("http://k")
Results:
false
false
false
true
false
false
true
true
false
false
false
use this-
NSString *urlRegEx = #"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";
I solved the problem using RegexKit, and build a quick regex to validate a URL;
NSString *regexString = #"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
NSString *subjectString = brandLink.text;
NSString *matchedString = [subjectString stringByMatching:regexString];
Then I check if the matchedString is equal to the subjectString and if that is the case the url is valid :)
Correct me if my regex is wrong ;)
I've found the easiest way to do this is like so:
- (BOOL)validateUrl: (NSURL *)candidate
{
NSURLRequest *req = [NSURLRequest requestWithURL:candidate];
return [NSURLConnection canHandleRequest:req];
}
Oddly enough, I didn't really find a solution here that was very simple, yet still did an okay job for handling http / https links.
Keep in mind, THIS IS NOT a perfect solution, but it worked for the cases below. In summary, the regex tests whether the URL starts with http:// or https://, then checks for at least 1 character, then checks for a dot, and then again checks for at least 1 character. No spaces allowed.
+ (BOOL)validateLink:(NSString *)link
{
NSString *regex = #"(?i)(http|https)(:\\/\\/)([^ .]+)(\\.)([^ \n]+)";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
return [predicate evaluateWithObject:link];
}
Tested VALID against these URLs:
#"HTTP://FOO.COM",
#"HTTPS://FOO.COM",
#"http://foo.com/blah_blah",
#"http://foo.com/blah_blah/",
#"http://foo.com/blah_blah_(wikipedia)",
#"http://foo.com/blah_blah_(wikipedia)_(again)",
#"http://www.example.com/wpstyle/?p=364",
#"https://www.example.com/foo/?bar=baz&inga=42&quux",
#"http://✪df.ws/123",
#"http://userid:password#example.com:8080",
#"http://userid:password#example.com:8080/",
#"http://userid#example.com",
#"http://userid#example.com/",
#"http://userid#example.com:8080",
#"http://userid#example.com:8080/",
#"http://userid:password#example.com",
#"http://userid:password#example.com/",
#"http://142.42.1.1/",
#"http://142.42.1.1:8080/",
#"http://➡.ws/䨹",
#"http://⌘.ws",
#"http://⌘.ws/",
#"http://foo.com/blah_(wikipedia)#cite-",
#"http://foo.com/blah_(wikipedia)_blah#cite-",
#"http://foo.com/unicode_(✪)_in_parens",
#"http://foo.com/(something)?after=parens",
#"http://☺.damowmow.com/",
#"http://code.google.com/events/#&product=browser",
#"http://j.mp",
#"http://foo.bar/?q=Test%20URL-encoded%20stuff",
#"http://مثال.إختبار",
#"http://例子.测试",
#"http://उदाहरण.परीक्षा",
#"http://-.~_!$&'()*+,;=:%40:80%2f::::::#example.com",
#"http://1337.net",
#"http://a.b-c.de",
#"http://223.255.255.254"
Tested INVALID against these URLs:
#"",
#"foo",
#"ftp://foo.com",
#"ftp://foo.com",
#"http://..",
#"http://..",
#"http://../",
#"//",
#"///",
#"http://##/",
#"http://.www.foo.bar./",
#"rdar://1234",
#"http://foo.bar?q=Spaces should be encoded",
#"http:// shouldfail.com",
#":// should fail"
Source of URLs:
https://mathiasbynens.be/demo/url-regex
You can use this if you do not want http or https or www
NSString *urlRegEx = #"^(http(s)?://)?((www)?\.)?[\w]+\.[\w]+";
example
- (void) testUrl:(NSString *)urlString{
NSLog(#"%#: %#", ([self isValidUrl:urlString] ? #"VALID" : #"INVALID"), urlString);
}
- (void)doTestUrls{
[self testUrl:#"google"];
[self testUrl:#"google.de"];
[self testUrl:#"www.google.de"];
[self testUrl:#"http://www.google.de"];
[self testUrl:#"http://google.de"];
}
Output:
INVALID: google
VALID: google.de
VALID: www.google.de
VALID: http://www.google.de
VALID: http://google.de
Lefakir's solution has one issue.
His regex can't match with "http://instagram.com/p/4Mz3dTJ-ra/".
Url component has combined numerical and literal character. His regex fail such urls.
Here is my improvement.
"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*)+)+(/)?(\\?.*)?"
Below code will let you find the valid URLs
NSPredicate *websitePredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",#"^(((((h|H)(t|T){2}(p|P)s?)|((f|F)(t|T)(p|P)))://(w{3}.)?)|(w{3}.))[A-Za-z0-9]+(.[A-Za-z0-9-:;\?#_]+)+"];
if ([websitePredicate evaluateWithObject:##MY_STRING##])
{
printf"Valid"
}
for such URLS
http://123.com
https://123.com
http://www.123.com
https://www.123.com
ftp://123.com
ftp://www.123.com
www.something.com
The approved answer is incorrect.
I have an URL with an "-" in it, and the validation fails.
Tweeked Vaibhav's answer to support G+ links:
NSString *urlRegEx = #"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-\\+ ./?%&=]*)?";
Some URL's without / at the end are not detected as the correct one in the solutions above. So this might be helpful.
extension String {
func isValidURL() -> Bool{
let length:Int = self.characters.count
var err:NSError?
var dataDetector:NSDataDetector? = NSDataDetector()
do{
dataDetector = try NSDataDetector(types: NSTextCheckingType.Link.rawValue)
}catch{
err = error as NSError
}
if dataDetector != nil{
let range = NSMakeRange(0, length)
let notFoundRange = NSRange(location: NSNotFound, length: 0)
let linkRange = dataDetector?.rangeOfFirstMatchInString(self, options: NSMatchingOptions.init(rawValue: 0), range: range)
if !NSEqualRanges(notFoundRange, linkRange!) && NSEqualRanges(range, linkRange!){
return true
}
}else{
print("Could not create link data detector: \(err?.localizedDescription): \(err?.userInfo)")
}
return false
}
}
URL Validation in Swift
Details
Xcode 8.2.1, Swift 3
Code
enum URLSchemes: String
import Foundation
enum URLSchemes: String {
case http = "http://", https = "https://", ftp = "ftp://", unknown = "unknown://"
static func detectScheme(urlString: String) -> URLSchemes {
if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .http) {
return .http
}
if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .https) {
return .https
}
if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .ftp) {
return .ftp
}
return .unknown
}
static func getAllSchemes(separetedBy separator: String) -> String {
return "\(URLSchemes.http.rawValue)\(separator)\(URLSchemes.https.rawValue)\(separator)\(URLSchemes.ftp.rawValue)"
}
private static func isSchemeCorrect(urlString: String, scheme: URLSchemes) -> Bool {
if urlString.replacingOccurrences(of: scheme.rawValue, with: "") == urlString {
return false
}
return true
}
}
extension String
import Foundation
extension String {
var isUrl: Bool {
// for http://regexr.com checking
// (?:(?:https?|ftp):\/\/)(?:xn--)?(?:\S+(?::\S*)?#)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[#-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?
let schemes = URLSchemes.getAllSchemes(separetedBy: "|").replacingOccurrences(of: "://", with: "")
let regex = "(?:(?:\(schemes)):\\/\\/)(?:xn--)?(?:\\S+(?::\\S*)?#)?(?:(?!10(?:\\.\\d{1,3}){3})(?!127(?:\\.\\d{1,3}){3})(?!169\\.254(?:\\.\\d{1,3}){2})(?!192\\.168(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[#-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?"
let regularExpression = try! NSRegularExpression(pattern: regex, options: [])
let range = NSRange(location: 0, length: self.characters.count)
let matches = regularExpression.matches(in: self, options: [], range: range)
for match in matches {
if range.location == match.range.location && range.length == match.range.length {
return true
}
}
return false
}
var toURL: URL? {
let urlChecker: (String)->(URL?) = { url_string in
if url_string.isUrl, let url = URL(string: url_string) {
return url
}
return nil
}
if !contains(".") {
return nil
}
if let url = urlChecker(self) {
return url
}
let scheme = URLSchemes.detectScheme(urlString: self)
if scheme == .unknown {
let newEncodedString = URLSchemes.http.rawValue + self
if let url = urlChecker(newEncodedString) {
return url
}
}
return nil
}
}
Usage
func tests() {
chekUrl(urlString:"http://example.com")
chekUrl(urlString:"https://example.com")
chekUrl(urlString:"http://example.com/dir/file.php?var=moo")
chekUrl(urlString:"http://xn--h1aehhjhg.xn--d1acj3b")
chekUrl(urlString:"http://www.example.com/wpstyle/?p=364")
chekUrl(urlString:"http://-.~_!$&'()*+,;=:%40:80%2f::::::#example.com")
chekUrl(urlString:"http://example.com")
chekUrl(urlString:"http://xn--d1acpjx3f.xn--p1ai")
chekUrl(urlString:"http://xn--74h.damowmow.com/")
chekUrl(urlString:"ftp://example.com:129/myfiles")
chekUrl(urlString:"ftp://user:pass#site.com:21/file/dir")
chekUrl(urlString:"ftp://ftp.example.com:2828/asdah%20asdah.gif")
chekUrl(urlString:"http://142.42.1.1:8080/")
chekUrl(urlString:"http://142.42.1.1/")
chekUrl(urlString:"http://userid:password#example.com:8080")
chekUrl(urlString:"http://userid#example.com")
chekUrl(urlString:"http://userid#example.com:8080")
chekUrl(urlString:"http://foo.com/blah_(wikipedia)#cite-1")
chekUrl(urlString:"http://foo.com/(something)?after=parens")
print("\n----------------------------------------------\n")
chekUrl(urlString:".")
chekUrl(urlString:" ")
chekUrl(urlString:"")
chekUrl(urlString:"-/:;()₽&#.,?!'{}[];'<>+_)(*#^%$")
chekUrl(urlString:"localhost")
chekUrl(urlString:"yandex.")
chekUrl(urlString:"коряга")
chekUrl(urlString:"http:///a")
chekUrl(urlString:"ftps://foo.bar/")
chekUrl(urlString:"rdar://1234")
chekUrl(urlString:"h://test")
chekUrl(urlString:":// should fail")
chekUrl(urlString:"http://-error-.invalid/")
chekUrl(urlString:"http://.www.example.com/")
}
func chekUrl(urlString: String) {
var result = ""
if urlString.isUrl {
result += "url: "
} else {
result += "not url: "
}
result += "\"\(urlString)\""
print(result)
}
Result
Objective C
- (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);
}
Hope this helps!
did you mean to check if what the user entered is a URL? It can be as simple as a regular expression, for example checking if the string contain www. (this is the way that yahoo messenger checks if the user status is a link or not)
Hope that help
Selfishly, I would suggest using a KSURLFormatter instance to both validate input, and convert it to something NSURL can handle.
I have created inherited class of UITextField which can handle all kind of validation using regex string. In this you just need to give them all the regex string in sequence and their message that you want to show when validation get failed. You can check my blog for more info, it will really help you
http://dhawaldawar.wordpress.com/2014/06/11/uitextfield-validation-ios/
Extending #Anthony's answer to swift, I wrote a category on String which returns an optional NSURL. The return value is nil if the String can not be validated to be a URL.
import Foundation
// A private global detector variable which can be reused.
private let detector = try! NSDataDetector(types: NSTextCheckingType.Link.rawValue)
extension String {
func URL() -> NSURL? {
let textRange = NSMakeRange(0, self.characters.count)
guard let URLResult = detector.firstMatchInString(self, options: [], range: textRange) else {
return nil
}
// This checks that the whole string is the detected URL. In case
// you don't have such a requirement, you can remove this code
// and return the URL from URLResult.
guard NSEqualRanges(URLResult.range, textRange) else {
return nil
}
return NSURL(string: self)
}
}
func checkValidUrl(_ strUrl: String) -> Bool {
let urlRegEx: String = "(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"
let urlTest = NSPredicate(format: "SELF MATCHES %#", urlRegEx)
return urlTest.evaluate(with: strUrl)
}
My solution in Swift 5:
extension String {
func isValidUrl() -> Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
// check if the string has link inside
return detector.numberOfMatches(in: self, options: [], range: .init( location: 0, length: utf16.count)) > 0
} catch {
print("Error during NSDatadetector initialization \(error)" )
}
return false
}
}

How to find out if an external headset is connected to an iPhone?

Is it possible to detect that the user has an external headset plugged into the iPhone's 3.5mm connector or the 30-pin connector? I want to output audio only to an external audio device, and keep silent if nothing is connected.
The answer is very similar to the answer to this question, but you'll want to get the kAudioSessionProperty_AudioRoute property instead.
Call this method to find out the bluetooth headset is connected or not.
First import this framework #import <AVFoundation/AVFoundation.h>
- (BOOL) isBluetoothHeadsetConnected
{
AVAudioSession *session = [AVAudioSession sharedInstance];
AVAudioSessionRouteDescription *routeDescription = [session currentRoute];
NSLog(#"Current Routes : %#", routeDescription);
if (routeDescription)
{
NSArray *outputs = [routeDescription outputs];
if (outputs && [outputs count] > 0)
{
AVAudioSessionPortDescription *portDescription = [outputs objectAtIndex:0];
NSString *portType = [portDescription portType];
NSLog(#"dataSourceName : %#", portType);
if (portType && [portType isEqualToString:#"BluetoothA2DPOutput"])
{
return YES;
}
}
}
return NO;
}
There is nice article about this in Apple documentation:
https://developer.apple.com/documentation/avfoundation/avaudiosession/responding_to_audio_session_route_changes
Only you have to verify if portType == AVAudioSessionPortBluetoothA2DP
func setupNotifications() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(handleRouteChange),
name: .AVAudioSessionRouteChange,
object: nil)
}
#objc func handleRouteChange(notification: Notification) {
guard let userInfo = notification.userInfo,
let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
return
}
switch reason {
case .newDeviceAvailable:
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = true
break
}
case .oldDeviceUnavailable:
if let previousRoute =
userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
for output in previousRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
headsetConnected = false
break
}
}
default: ()
}
}
func isBluetoothHeadsetConnected() -> Bool {
var result = false
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortBluetoothA2DP {
result = true
}
return result
}