W rozwijanej przeze mnie aplikacji na iPhone'a istnieje ustawienie, w którym można wprowadzić adres URL, ponieważ ze względu na formę i funkcję ten adres URL musi zostać zweryfikowany zarówno w trybie online, jak i offline.
Jak dotąd nie udało mi się znaleźć żadnej metody weryfikacji adresu URL, więc pytanie brzmi;
Jak sprawdzić poprawność wprowadzonego adresu URL w telefonie iPhone (Objective-C) zarówno w trybie online, jak i offline?
Odpowiedzi:
Dzięki temu wpisowi możesz uniknąć korzystania z RegexKit. Oto moje rozwiązanie (działa przy programowaniu na iPhone'a z 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]; }
Jeśli chcesz sprawdzić w Swift moje rozwiązanie podane poniżej:
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 }
źródło
((http|https)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"
Powinien sprawić, że http: // lub https: // będzie opcjonalne.Dlaczego zamiast tego po prostu nie polegać
Foundation.framework
?To spełnia swoje zadanie i nie wymaga
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) }
Zgodnie z dokumentacją Apple:
źródło
http://www.aol.comhttp://www.nytimes.com
przechodzi ten test.NSURL
nie zwraca nil, gdy przekażę ciąg @ "# @ # @ $ ##% $ # $ #" lub @ "tp: / fdfdfsfdsf". Więc ta metoda będzie bezużyteczna do sprawdzania poprawnych adresów URL HTTP i tym podobnych.Zamiast pisać własne wyrażenia regularne, polegaj na Apple. Używałem kategorii,
NSString
która używaNSDataDetector
do testowania obecności linku w ciągu. Jeśli zakres linku znalezionego przezNSDataDetector
jest równy długości całego ciągu, to jest to prawidłowy adres 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; }
źródło
Moje rozwiązanie ze 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) }
Dla testu:
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")
Wyniki:
false false false true false false true true false false false
źródło
Użyj tego-
NSString *urlRegEx = @"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";
źródło
www.google.com/+gplusname
Rozwiązałem problem za pomocą RegexKit i zbudowałem szybkie wyrażenie regularne do walidacji adresu URL;
NSString *regexString = @"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"; NSString *subjectString = brandLink.text; NSString *matchedString = [subjectString stringByMatching:regexString];
Następnie sprawdzam, czy matchedString jest równa subjectString i jeśli tak jest, adres URL jest prawidłowy :)
Popraw mnie, jeśli moje wyrażenie regularne jest błędne;)
źródło
Co dziwne, tak naprawdę nie znalazłem tutaj rozwiązania, które byłoby bardzo proste, a mimo to dobrze sobie radziłem z obsługą
http
/https
linkami.Pamiętaj, to NIE JEST TO idealne rozwiązanie, ale zadziałało w poniższych przypadkach. Podsumowując, wyrażenie regularne sprawdza, czy adres URL zaczyna się od
http://
lubhttps://
, następnie sprawdza, czy zawiera co najmniej 1 znak, a następnie sprawdza, czy nie ma kropki, a następnie ponownie sprawdza, czy zawiera co najmniej 1 znak. Brak spacji.+ (BOOL)validateLink:(NSString *)link { NSString *regex = @"(?i)(http|https)(:\\/\\/)([^ .]+)(\\.)([^ \n]+)"; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; return [predicate evaluateWithObject:link]; }
Przetestowane WAŻNE dla tych adresów URL:
@"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:[email protected]:8080", @"http://userid:[email protected]:8080/", @"http://[email protected]", @"http://[email protected]/", @"http://[email protected]:8080", @"http://[email protected]:8080/", @"http://userid:[email protected]", @"http://userid:[email protected]/", @"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"
Testowane jako NIEPRAWIDŁOWE dla tych adresów URL:
@"", @"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"
Źródło adresów URL: https://mathiasbynens.be/demo/url-regex
źródło
Możesz użyć tego, jeśli nie chcesz
http
lubhttps
lubwww
NSString *urlRegEx = @"^(http(s)?://)?((www)?\.)?[\w]+\.[\w]+";
przykład
- (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"]; }
Wynik:
INVALID: google VALID: google.de VALID: www.google.de VALID: http://www.google.de VALID: http://google.de
źródło
Rozwiązanie Lefakira ma jeden problem. Jego wyrażenie regularne nie pasuje do „ http://instagram.com/p/4Mz3dTJ-ra/ ”. Składnik adresu URL łączy znaki numeryczne i literalne. Jego wyrażenie regularne nie zawiera takich adresów URL.
Oto moja poprawa.
"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*)+)+(/)?(\\?.*)?"
źródło
Odkryłem, że najłatwiej to zrobić w następujący sposób:
- (BOOL)validateUrl: (NSURL *)candidate { NSURLRequest *req = [NSURLRequest requestWithURL:candidate]; return [NSURLConnection canHandleRequest:req]; }
źródło
NSURL
, więc może zostać sprawdzone zamiast tego. A mimo to używa starego API.Poniższy kod pozwoli Ci znaleźć prawidłowe adresy URL
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" }
dla takich adresów URL
źródło
Zatwierdzona odpowiedź jest nieprawidłowa. Mam adres URL zawierający znak „-”, a weryfikacja kończy się niepowodzeniem.
źródło
Odpowiedź Vaibhava na Twitterze dotycząca obsługi linków G +:
NSString *urlRegEx = @"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-\\+ ./?%&=]*)?";
źródło
Niektóre adresy URL bez końcówki / na końcu nie są wykrywane jako poprawne w powyższych rozwiązaniach. Więc to może być pomocne.
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 } }
źródło
Walidacja adresu URL w Swift
Detale
Xcode 8.2.1, Swift 3
Kod
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 } }
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 } }
Stosowanie
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:[email protected]: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:[email protected]:8080") chekUrl(urlString:"http://[email protected]") chekUrl(urlString:"http://[email protected]: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) }
Wynik
źródło
Cel 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); }
Mam nadzieję że to pomoże!
źródło
czy chodziło Ci o sprawdzenie, czy wpisany przez użytkownika adres jest adresem URL? Może być tak proste, jak wyrażenie regularne, na przykład sprawdzanie, czy ciąg zawiera
www.
(w ten sposób komunikator yahoo sprawdza, czy status użytkownika to link, czy nie).Mam nadzieję, że to pomoże
źródło
Samolubnie sugerowałbym użycie
KSURLFormatter
instancji zarówno do walidacji danych wejściowych, jak i przekonwertowania ich na coś, coNSURL
może obsłużyć.źródło
Stworzyłem odziedziczoną klasę UITextField, która może obsłużyć wszelkiego rodzaju walidację za pomocą ciągu regex. W tym celu wystarczy podać im wszystkie ciągi wyrażeń regularnych w kolejności i ich wiadomość, którą chcesz pokazać, gdy walidacja się nie powiedzie. Możesz sprawdzić mój blog, aby uzyskać więcej informacji, to naprawdę ci pomoże
http://dhawaldawar.wordpress.com/2014/06/11/uitextfield-validation-ios/
źródło
Rozszerzając odpowiedź @ Anthony'ego na swift, napisałem kategorię, w
String
której zwraca wartość opcjonalnąNSURL
. Wartość zwracana jestnil
wtedy, gdyString
nie można zweryfikować, czy jest to adres 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) } }
źródło
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) }
źródło
Moje rozwiązanie w 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 } }
źródło