2011-01-19 27 views
5

Tôi đã tìm thấy cụm từ thông dụng này trên trang web. Nó được cho là biểu thức xác thực URL tốt nhất hiện có và tôi đồng ý. Diego Perini đã tạo ra nó.NSRegularExpression để xác thực URL

Vấn đề tôi đang gặp phải là khi cố gắng sử dụng nó với objective-C để phát hiện URL trên chuỗi. Tôi đã thử sử dụng các tùy chọn như NSRegularExpressionAnchorsMatchLines, NSRegularExpressionIgnoreMetacharacters và những người khác, nhưng vẫn không có may mắn.

Biểu thức không được định dạng tốt cho Objective-C? Tui bỏ lỡ điều gì vậy? Bất kỳ ý tưởng?

Tôi cũng đã thử dùng regex của John Gruber, nhưng không thành công với một số URL không hợp lệ.

 Regular Expression         Explanation of expression      

^             match at the beginning 
//Protocol identifier 
(?: 
    (?:https?|ftp         http, https or ftp 
    ):\\/\\/          :// 
)?             optional 
// User:Pass authentication 
(?: 
    ^\\s+           non white spaces, 1 or more times 
    (?: 
     :^\\s*          : non white spaces, 0 or more times, optionally 
    )[email protected]            @ 
)?             optional 
//Private IP Addresses        ?! Means DO NOT MATCH ahead. So do not match any of the following 
(?: 
    (?!10           10               10.0.0.0 - 10.999.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, three times 
     ){3} 
    ) 
    (?!127           127               127.0.0.0 - 127.999.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, three times 
     ){3} 
    ) 
    (?!169\\.254         169.254              169.254.0.0 - 169.254.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, two times 
     ){2} 
    ) 
    (?!192\\.168         192.168              192.168.0.0 - 192.168.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, two times 
     ){2} 
    ) 
    (?!172\\.          172.              172.16.0.0 - 172.31.999.999 
     (?:                            
      1[6-9]         1 followed by any number between 6 and 9 
      |          or 
      2\\d         2 and any digit 
      |          or 
      3[0-1]         3 followed by a 0 or 1 
     ) 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, two times 
     ){2} 
    ) 
    //First Octet IPv4        // match these. Any non network or broadcast IPv4 address 
    (?: 
     [1-9]\\d?         any number from 1 to 9 followed by an optional digit  1 - 99 
     |           or 
     1\\d\\d          1 followed by any two digits        100 - 199 
     |           or 
     2[01]\\d         2 followed by any 0 or 1, followed by a digit    200 - 219 
     |           or 
     22[0-3]          22 followed by any number between 0 and 3     220 - 223 
    ) 
    //Second and Third Octet IPv4 
    (?: 
     \\.           . 
     (?: 
      1?\\d{1,2}        optional 1 followed by any 1 or two digits     0 - 199 
      |          or 
      2[0-4]\\d        2 followed by any number between 0 and 4, and any digit  200 - 249 
      |          or 
      25[0-5]         25 followed by any numbers between 0 and 5     250 - 255 
     ) 
    ){2}           two times 
    //Fourth Octet IPv4 
    (?: 
     \\.           . 
     (?: 
      [1-9]\\d?        any number between 1 and 9 followed by an optional digit 1 - 99 
      |          or 
      1\\d\\d         1 followed by any two digits        100 - 199 
      |          or 
      2[0-4]\\d        2 followed by any number between 0 and 4, and any digit  200 - 249 
      |          or 
      25[0-4]         25 followed by any number between 0 and 4     250 - 254 
     ) 
    ) 
    //Host name 
    |            or     
    (?: 
     (?: 
      [a-z\u00a1-\uffff0-9]+-?    any letter, digit or character one or more times with optional - 
     )*           zero or more times 
     [a-z\u00a1-\uffff0-9]+      any letter, digit or character one or more times 
    ) 
    //Domain name 
    (?: 
     \\.           . 
     (?: 
      [a-z\u00a1-\uffff0-9]+-?    any letter, digit or character one or more times with optional - 
     )*           zero or more times 
     [a-z\u00a1-\uffff0-9]+      any letter, digit or character one or more times 
    )*            zero or more times 
    //TLD identifier 
    (?: 
     \\.           . 
     (?: 
      [a-z\u00a1-\uffff]{2,}     any letter, digit or character more than two times 
     ) 
    ) 
) 
//Port number 
(?: 
    :\\d{2,5}          : followed by any digit, two to five times, optionally 
)?    
//Resource path 
(?: 
    \\/[^\\s]*         /followed by an optional non space character, zero or more times 
)?             optional 
$             match at the end 

EDIT Tôi nghĩ rằng tôi quên nói rằng tôi đang sử dụng các biểu hiện trong đoạn mã sau: (mã một phần)

NSError *error = NULL; 
NSRegularExpression *detector = [NSRegularExpression regularExpressionWithPattern:[self theRegularExpression] options:0 error:&error]; 
NSArray *links = [detector matchesInString:theText options:0 range:NSMakeRange(0, theText.length)]; 

Trả lời

9
^(?i)(?:(?:https?|ftp):\\/\\/)?(?:\\S+(?::\\S*)[email protected])?(?:(?:[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]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?$ 

Biểu thức chính quy xác thực URL tốt nhất mà tôi tìm thấy và được giải thích trong câu hỏi của tôi. Nó đã được định dạng để hoạt động trên Objective-C. Tuy nhiên, sử dụng nó với NSRegularExpression đã cho tôi tất cả các loại sự cố, kể cả ứng dụng của tôi bị lỗi. RegexKitLite không gặp sự cố khi xử lý. Tôi không biết nếu nó là một giới hạn kích thước hoặc một số lá cờ không được thiết lập. mã cuối cùng của tôi trông giống như:

//First I take the string and put every word in an array, then I match every word with the regular expression 
NSArray *splitIntoWordsArray = [textToMatch componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewLineCharacterSet]]; 
NSMutableString *htmlString = [NSMutableString stringWithString:textToMatch]; 
for (NSString *theText in splitIntoWordsArray){ 
    NSEnumerator *matchEnumerator = [theText matchEnumeratorWithRegex:theRegularExpressionString]; 
    for (NSString *temp in matchEnumerator){ 
     [htmlString replaceOccurrencesOfString:temp withString:[NSString stringWithFormat:@"<a href=\"%@\">%@</a>", temp, temp] options:NSLiteralSearch range:NSMakeRange(0, [htmlString length])]; 
    } 
} 
[htmlString replaceOccurrencesOfString:@"\n" withString:@"<br />" options:NSLiteralSearch range:NSMakeRange(0, htmlString.length)]; 
//embed the text on a webView as HTML 
[webView loadHTMLString:[NSString stringWithFormat:embedHTML, [mainFont fontName], [mainFont pointSize], htmlString] baseURL:nil]; 

Kết quả: a UIWebView với một số HTML nhúng, nơi URL và email đều có thể click. Đừng quên để thiết lập dataDetectorTypes = UIDataDetectorTypeNone

Bạn cũng có thể thử

NSError *error = NULL; 
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"(?i)(?:(?:https?):\\/\\/)?(?:\\S+(?::\\S*)[email protected])?(?:(?:[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]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?" options:NSRegularExpressionCaseInsensitive error:&error]; 
if (error) 
    NSLog(@"error"); 
NSString *someString = @"This is a sample of a sentence with a URL http://. http://.. http://../ http://? http://?? http://??/ http://# http://-error-.invalid/ http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com within it."; 
NSRange range = [expression rangeOfFirstMatchInString:someString options:NSMatchingCompleted range:NSMakeRange(0, [someString length])]; 
if (!NSEqualRanges(range, NSMakeRange(NSNotFound, 0))){ 
    NSString *match = [someString substringWithRange:range]; 
    NSLog(@"%@", match); 
} 
else { 
    NSLog(@"no match"); 
} 

Hy vọng nó sẽ giúp ai đó trong

Các biểu hiện thường xuyên trong tương lai đôi khi sẽ gây ra các ứng dụng để treo, vì vậy tôi quyết định sử dụng Gruber của thường xuyên biểu thức được sửa đổi để nhận ra url không có giao thức hoặc phần www:

(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))*(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’])*) 
+0

Cảm ơn anh chàng vì bài tốt. – Jhaliya

+0

Mã gruber được cập nhật của bạn tốt, tuy nhiên nó không khớp với "google.com" - tuy nhiên, nó khớp với "google.comm" và "google.co.uk" - bất kỳ ý tưởng nào để tinh chỉnh điều đó? – mootymoots

+0

Rất cám ơn nhiều vì biểu thức chính quy. Nó thật là tuyệt vời. –

7

Tôi có thiếu cái gì?

Bạn đang thiếu công cụ tích hợp để thực hiện việc này cho bạn. Có một vật dụng tiện dụng gọi là NSDataDetector. Bạn tạo nó để tìm một số loại dữ liệu nhất định (ví dụ: NSTextCheckingTypeLink), sau đó hỏi nó cho số -matchesInString:options:range: của nó.

Here's an earlier answer of mine showing how to use it.

+0

Cảm ơn bạn đã trả lời nhanh chóng. Tôi đã thử nó trước đây, nhưng nó không nhận ra một số URL, như .asia, .info, vv Đó là khi URL không được định dạng tốt như http://healthyhomes.asia Đây là lý do tại sao tôi sử dụng thường xuyên biểu hiện. Sử dụng trình kiểm tra trực tuyến, nó phát hiện healthhomes.asia hoặc info.info với phần giao thức của bạn. – GianPac

+0

@Dave DeLong không thành công trong trường hợp cập nhật www.google.c – JAHelia

+0

năm 2017: chỉ cần chọn NSDataDetector. 'info.info' hiện đang hoạt động, nhưng' healthhomes.asia' vẫn không hoạt động. 'www.google.c' DOES hoạt động. Không biết Safari (iOS và máy tính để bàn) có thể truy cập vào 'healthhomes.asia' như thế nào nếu' NSDataDetector' của 'Foundation' không hỗ trợ một URL như vậy. –

Các vấn đề liên quan