2010-10-15 24 views
5

Tôi đang sử dụng regex để tìm bất kỳ URL nào và liên kết chúng theo đó. Tuy nhiên, tôi không muốn liên kết bất kỳ URL nào đã được liên kết, vì vậy tôi đang sử dụng lookbehind để xem liệu URL có một href trước đó hay không. Điều này không thành công mặc dù định lượng độ dài biến đổi không được phép trong lookahead và lookbehind cho PHP.lookbehind tiêu cực và định lượng tham lam trong php

Đây là regex cho trận đấu:

/\b(?<!href\s*=\s*[\'\"])((?:http:\/\/|www\.)\S*?)(?=\s|$)/i 

cách tốt nhất xung quanh vấn đề này là gì?

EDIT:

tôi vẫn chưa kiểm tra nó, nhưng tôi nghĩ các trick để làm việc đó trong một regex duy nhất được sử dụng biểu thức điều kiện trong regex, được hỗ trợ bởi PCRE. Nó sẽ giống như thế này:

/(href\s*=\s*[\'\"])?(?(1)^|)((?:http:\/\/|www\.)\w[\w\d\.\/]*)(?=\s|$)/i 

Điểm mấu chốt là nếu href được chụp, trận đấu được ngay lập tức ném ra do điều kiện (?(1)^|), được đảm bảo để không khớp nhau. Có thể có điều gì đó sai trái với nó. Tôi sẽ kiểm tra nó vào ngày mai.

+4

Um, sử dụng trình phân tích cú pháp HTML và chỉ liên kết khi đó là nút văn bản? – kennytm

+0

Đó có lẽ là giải pháp tốt nhất. Tôi đã tò mò hơn để xem nếu có một cách để điều chỉnh regex mặc dù. –

+0

+1 câu hỏi hay. – NikiC

Trả lời

1

tôi đã cố gắng làm điều tương tự theo chiều ngược lại: đảm bảo rằng URL không kết thúc trong ">:

/((?:http:\/\/|www\.)(?:[^"\s]|"[^>]|(*FAIL))*?)(?=\s|$)/i 

Nhưng đối với tôi trông khá hacky, tôi chắc chắn rằng bạn có thể làm tốt hơn.

cách tiếp cận thứ hai của tôi cũng tương tự như nhiều như của bạn (và do đó là chính xác hơn):

/href\s*=\s*"[^"]*"(*SKIP)(*FAIL)|((?:http:\/\/|www\.)\S*?)(?=\s|$)/i 

Nếu tôi tìm thấy một href= tôi (*SKIP)(*FAIL). Điều này có nghĩa là tôi nhảy đến vị trí của động cơ regex, khi nó gặp (*SKIP).

Nhưng đó không phải là ít hacky và tôi chắc chắn có một lựa chọn tốt hơn.

+0
+0

@steven_desu: Đó là lý do tại sao tôi sẽ liên kết với phiên bản thứ hai;) – NikiC

0

Tôi không có regex tốt hơn. nhưng nếu bạn không tìm thấy regex tốt hơn thì tôi sẽ đề nghị sử dụng hai truy vấn cho nhiệm vụ. Trước tiên, hãy tìm và xóa tất cả các liên kết và sau đó tìm kiếm các url. Điều này sẽ dễ dàng hơn và nhanh hơn có thể. (Đối với, tìm và thay thế trong một lần, bạn có thể sử dụng một cái gì đó như - http://www.satya-weblog.com/2010/08/php-regex-find-and-replace-any-word-string-or-text-at-one-go.html).

0

Tìm "mọi URL không phải là một phần của liên kết" là logic âm khó khá. Có thể dễ dàng tìm thấy mọi URL hơn, sau đó mỗi URL là một liên kết và xóa mọi URL sau khỏi danh sách trước đó.

Theo như phát hiện các URL một phần của một liên kết, hãy thử:

/<a([\s]+[\w="]+)*[\s]+href[\s]*=[\s]*"([\w\s:/.?+&=]+)"([\s]+[\w="]+)*>/i 

Tôi đã thử nghiệm nó với http://regexpal.com/ để đảm bảo. Nó tìm kiếm các <a đầu tiên, sau đó nó cho phép cho bất kỳ số lượng các tham số, theo sau là href, tiếp theo là bất kỳ số lượng khác của các tham số. Nếu nó không có href, nó không phải là một liên kết. Nếu nó không phải là một thẻ <a>, nó không phải là một liên kết. Vì đây chỉ là danh sách những gì chúng tôi muốn xóa khỏi danh sách khác (của URL), tôi đã đơn giản hóa định nghĩa của URL thành [\w\s:/.?+&=]+. Theo như tạo ra một danh sách các URL, bạn sẽ muốn một cái gì đó thông minh hơn.

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