2008-11-13 31 views
20

Tôi có tải nội dung do người dùng gửi. Đó là HTML và có thể chứa URL. Một số người trong số họ sẽ là <a> đã có (nếu người dùng là tốt) nhưng đôi khi người dùng là lười biếng và chỉ cần gõ www.something.com hoặc tốt nhất http://www.something.com.Cần regex tốt để chuyển đổi URL thành liên kết nhưng chỉ để lại các liên kết hiện tại

Tôi không thể tìm thấy một regex phong nha để nắm bắt URL nhưng bỏ qua những người ngay lập tức ở bên phải của một dấu ngoặc kép hoặc '>'. Có ai có không?

Trả lời

14

Jan Goyvaerts, tác giả của RegexBuddy, có written a response vào blog của Jeff Atwood giải quyết các vấn đề mà Jeff có và cung cấp giải pháp tốt đẹp.

\b(?:(?:https?|ftp|file)://|www\.|ftp\.)[-A-Z0-9+&@#/%=~_|$?!:,.]*[A-Z0-9+&@#/%=~_|$] 

Để bỏ qua các trận đấu diễn ra ngay bên cạnh một "hoặc>, bạn có thể thêm (?<![">]) đến sự bắt đầu của regex, vì vậy bạn sẽ có được

(?<![">])\b(?:(?:https?|ftp|file)://|www\.|ftp\.)[-A-Z0-9+&@#/%=~_|$?!:,.]*[A-Z0-9+&@#/%=~_|$] 

này sẽ phù hợp địa chỉ đầy đủ (http://.. .) và địa chỉ bắt đầu bằng www. hoặc ftp. - bạn không may mắn với các địa chỉ như ars.userfriendly.org ...

0

Phích cắm không biết xấu hổ: Bạn có thể xem tại đây (regular expression replace a word by a link) để lấy cảm hứng

Câu hỏi được yêu cầu thay thế một số từ bằng một liên kết nhất định, trừ khi đã có liên kết. Vì vậy, vấn đề bạn có là nhiều hơn hoặc ít hơn cùng một điều.

Tất cả những gì bạn cần là một regex khớp với URL (thay cho từ). Giả định đơn giản nhất sẽ là như sau: URL (tùy chọn) bắt đầu bằng "http://", "ftp://" hoặc "mailto:" và kéo dài miễn là không có ký tự trắng, dấu ngắt dòng, dấu ngoặc kép hoặc dấu ngoặc kép).

Hãy coi chừng, regex dài phía trước. Áp dụng phân biệt chữ hoa chữ thường.

(href\s*=\s*['"]?)?((?:http://|ftp://|mailto:)?[^.,<>"'\s\r\n\t]+(?:\.(?![.<>"'\s\r\n])[^.,!<>"'\s\r\n\t]+)+) 

Được cảnh báo - điều này cũng sẽ phù hợp với URL là kỹ thuật không hợp lệ, và nó sẽ nhận ra things.formatted.like.this như một URL. Nó phụ thuộc vào dữ liệu của bạn nếu nó quá nhạy cảm. Tôi có thể tinh chỉnh regex nếu bạn có các ví dụ trong đó nó trả về các kết quả dương tính giả.

Regex sẽ tạo hai nhóm đối sánh. Nhóm 2 sẽ chứa nội dung phù hợp, rất có thể là URL. Nhóm 1 sẽ chứa một chuỗi rỗng hoặc 'href="'. Bạn có thể sử dụng nó làm chỉ báo rằng kết quả trùng khớp này xảy ra bên trong thông số a href của liên kết hiện tại và bạn không phải chạm vào liên kết đó.

Khi bạn xác nhận rằng điều này phù hợp với bạn hầu hết thời gian (với dữ liệu do người dùng cung cấp, bạn không bao giờ có thể chắc chắn), bạn có thể thực hiện phần còn lại theo hai bước. câu hỏi:

  1. Thực hiện một liên kết xung quanh mỗi URL có (trừ có cái gì đó trong nhóm trận đấu 1!) Đây sẽ sản xuất đôi lồng nhau <a> thẻ cho những điều mà có một liên kết rồi.
  2. Scan for lồng nhau đúng <a> thẻ, loại bỏ trong cùng một
0

Để bỏ qua hiện những chỉ cần sử dụng một cái nhìn phía sau - thêm (?<!href=") đến đầu biểu hiện thường xuyên của bạn, vì vậy nó sẽ giống như thế này:

/(?<!href=")http://\S*/ 

Rõ ràng đây không phải là giải pháp hoàn chỉnh cho việc tìm kiếm tất cả các loại URL, nhưng điều này sẽ giải quyết được vấn đề của bạn với các URL hiện có.

10

tôi đã thực hiện một thay đổi nhỏ về Regex chứa trong câu trả lời ban đầu:

(?<![.*">])\b(?:(?:https?|ftp|file)://|[a-z]\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$] 

cho phép để biết thêm tên miền phụ, và cũng có thể chạy một kiểm tra đầy đủ hơn trên thẻ. Để áp dụng điều này cho preg của PHP thay thế, bạn có thể sử dụng:

$convertedText = preg_replace('@(?<![.*">])\b(?:(?:https?|ftp|file)://|[a-z]\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$]@i', '<a href="\0" target="_blank">\0</a>', $originalText); 

Lưu ý, tôi đã xóa @ khỏi regex, để sử dụng nó làm dấu phân cách cho preg_replace. Khá hiếm khi @ sẽ được sử dụng trong URL.

Rõ ràng, bạn có thể sửa đổi các văn bản thay thế, và loại bỏ target = "_ blank", hoặc thêm rel = "nofollow" vv

Hy vọng rằng sẽ giúp.

+0

Tôi đã thêm một = vào (? ]) khi bắt đầu không ngắt link (thẻ neo không được trích dẫn). Nice regex btw :) – Joel

+0

@ Joel: Bạn có chắc chắn rằng bạn muốn điều đó có nghĩa là "Xác nhận rằng không thể kết hợp dấu chấm, dấu hoa thị, dấu ngoặc kép hoặc dấu ngoặc nhọn trước vị trí hiện tại trong chuỗi"? –

11

Chủ đề này cũ như những ngọn đồi, nhưng tôi bắt gặp nó trong khi làm việc về vấn đề của riêng mình: Đó là, chuyển đổi bất kỳ url thành liên kết, nhưng để lại một mình bất kỳ đã có trong các thẻ neo. Sau một thời gian, đây là những gì đã xuất hiện ra:

(?!(?!.*?<a)[^<]*<\/a>)(?:(?:https?|ftp|file)://|www\.|ftp\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$] 

Với đầu vào như sau:

http://www.google.com 
http://google.com 
www.google.com 

<p>http://www.google.com<p> 

this is a normal sentence. let's hope it's ok. 

<a href="http://www.google.com">www.google.com</a> 

Đây là sản phẩm của một preg_replace:

<a href="http://www.google.com" rel="nofollow">http://www.google.com</a> 
<a href="http://google.com" rel="nofollow">http://google.com</a> 
<a href="www.google.com" rel="nofollow">www.google.com</a> 

<p><a href="http://www.google.com" rel="nofollow">http://www.google.com</a><p> 

this is a normal sentence. let's hope it's ok. 

<a href="http://www.google.com">www.google.com</a> 

Chỉ muốn đóng góp trở lại để cứu ai đó một thời gian.

+5

Điều này làm việc cho tôi. Bạn là một nhà vô địch! Đã thêm cờ 'i' và đây là kết quả php: '$ text = preg_replace ('@ (?! (?!. *? ) (?: (?: Https? | Ftp | file): // | www \. | ftp \.) [- A-Z0-9 + & # /% = ~ _ | $?!:,.] * [A-Z0-9 + & # /% = ~ _ | $] @ i ',' \0 ', $ text); 'các giải pháp khác ở trên không hiệu quả đối với tôi trong mọi trường hợp. – dtbaker

1
if (preg_match('/\b(?<!=")(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[A-Z0-9+&@#\/%=~_|](?!.*".*>)(?!.*<\/a>)/i', $subject)) { 
    # Successful match 
} else { 
    # Match attempt failed 
} 
Các vấn đề liên quan