Jak zastąpić zwykłe adresy URL linkami?


453

Korzystam z funkcji poniżej, aby dopasować adresy URL w danym tekście i zastąpić je linkami HTML. Wyrażenie regularne działa świetnie, ale obecnie zastępuję tylko pierwsze dopasowanie.

Jak mogę zastąpić cały adres URL? Wydaje mi się, że powinienem używać polecenia exec , ale tak naprawdę nie wymyśliłem, jak to zrobić.

function replaceURLWithHTMLLinks(text) {
    var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/i;
    return text.replace(exp,"<a href='$1'>$1</a>"); 
}

Odpowiedzi:


350

Po pierwsze, rzutowanie własnego wyrażenia regularnego na parsowanie adresów URL to straszny pomysł . Musisz sobie wyobrazić, że jest to dość powszechny problem, że ktoś napisał, debugował i przetestował dla niego bibliotekę, zgodnie z RFC . Identyfikatory URI są złożone - sprawdź kod do analizowania adresów URL w Node.js i stronę Wikipedia na temat schematów URI .

Istnieje mnóstwo skrajnych przypadków, jeśli chodzi o parsowanie adresów URL: międzynarodowe nazwy domen , rzeczywiste ( .museum) vs. nieistniejące ( .etc) TLD, dziwna interpunkcja, w tym nawiasy , interpunkcja na końcu adresu URL, nazwy hostów IPV6 itp.

Szukałem na tonę z bibliotek , i istnieje kilka warto skorzystać pomimo pewnych wad:

Biblioteki, które zdyskwalifikowałem szybko za to zadanie:

Jeśli nalegasz na wyrażenie regularne, najbardziej wyczerpującym jest wyrażenie regularne URL z komponentu , chociaż fałszywie wykryje niektóre nieistniejące dwuliterowe domeny TLD, patrząc na nie.


3
Szkoda, że URL regexp from Componentnie zostało to skomentowane, pomocne byłoby wyjaśnienie tego, co robi. Autolinker.jsjest bardzo dobrze skomentowany i ma testy. urlize.jsBiblioteka związana w odpowiedzi Vebjørn Ljosa jest również wygląda potężniejszy i dobrze utrzymane, mimo że nie ma testów.
Sam Hasler

1
Regex101.com automatycznie „wyjaśnia” wyrażenie regularne , ale powodzenia :) Szybko znalazłem również przypadek awarii z nieprawidłową TLD (ten sam link).
Dan Dascalescu

1
@SamHasler: Autolinker wymaga ulepszeń w obszarach TLD i IDN. Dodano kilka testów .
Dan Dascalescu

2
Ciekawe, że nikt nie wspomniał o wysiłkach Johna Grubera w utrzymaniu wzorca wyrażenia regularnego w adresie URL . Nie jest to jedyne / idealne rozwiązanie problemu, ale w każdym razie warto je zbadać, jeśli wprowadzasz własne rozwiązanie. Chciałem tylko dodać to jako odniesienie.
oelna

2
@DanDascalescu Spójrz na ten markdown-it.github.io/linkify-it . Ta biblioteka koncentruje się dokładnie na jednym zadaniu - wykrywaniu wzorców linków w tekście. Ale mam nadzieję, że robi to dobrze. Na przykład ma poprawną obsługę Unicode, w tym znaków astralnych. I obsługuje międzynarodowe domeny TLD.
Witalij

285

Zastępowanie adresów URL linkami (odpowiedź na ogólny problem)

Wyrażenie regularne w pytaniu pomija wiele przypadkowych przypadków. Podczas wykrywania adresów URL zawsze lepiej jest używać specjalistycznej biblioteki, która obsługuje międzynarodowe nazwy domen, nowe TLD, takie jak .museum, nawiasy i inne znaki interpunkcyjne w adresie URL i na końcu oraz wiele innych przypadków na krawędzi. Zobacz post na blogu Jeffa Atwooda Problem z adresami URL, aby uzyskać wyjaśnienie niektórych innych problemów.

Najlepsze podsumowanie bibliotek pasujące URL jest Dan Dăscălescu na Odpowiedź+100
(od lutego 2014)


„Spraw, aby wyrażenie regularne zastępowało więcej niż jedno dopasowanie” (odpowiedź na konkretny problem)

Dodaj „g” na końcu wyrażenia regularnego, aby umożliwić dopasowanie globalne:

/ig;

Ale to tylko rozwiązuje problem w pytaniu, w którym wyrażenie regularne zastępowało tylko pierwsze dopasowanie. Nie używaj tego kodu.


150

Wprowadziłem kilka drobnych modyfikacji w kodzie Travisa (aby uniknąć niepotrzebnej ponownej deklaracji - ale działa świetnie na moje potrzeby, więc dobra robota!):

function linkify(inputText) {
    var replacedText, replacePattern1, replacePattern2, replacePattern3;

    //URLs starting with http://, https://, or ftp://
    replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
    replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');

    //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
    replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');

    //Change email addresses to mailto:: links.
    replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
    replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return replacedText;
}

1
jak edytować ten kod, aby nie szkodzić osadzonym obiektom i elementom iframe .. (osadzone obiekty youtube i
element

5
W kodzie jest błąd, który pasuje tutaj do adresów e-mail. [a-zA-Z]{2,6}powinien przeczytać coś podobnego do (?:[a-zA-Z]{2,6})+, aby dopasować bardziej skomplikowane nazwy domen, np. email@example.co.uk.
Roshambo,

1
Mam problemy; najpierw po prostu http: // lub http: // www (bez spacji www nawet SO analizuje to źle najwyraźniej) utworzy link. I linki z http: // www. domena . com (bez spacji) utworzy jedno puste łącze, a następnie jedno z dołączonym tagiem zamykającym kotwicę w polu href.
Alfred

1
Co z adresami URL bez http://lub www? Czy to zadziała dla tego rodzaju adresów URL?
Nathan

2
Próbowałem edytować oryginalny post, aby naprawić problem mailto, ale muszę dodać co najmniej 6 znaków, aby dokonać edycji. Ale jeśli zmienisz ten wiersz: replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim;dzięki temu replacePattern3 = /(\w+@[a-zA-Z_]+?(\.[a-zA-Z]{2,6})+)/gim;
naprawisz

70

Dokonałem pewnych optymalizacji Linkify()powyższego kodu Travisa . Naprawiłem również błąd polegający na tym, że adresy e-mail z formatami typów poddomen nie były dopasowane (np. Przykład@domena.co.uk).

Ponadto zmieniłem implementację na prototypowanie Stringklasy, aby elementy można było dopasować w następujący sposób:

var text = 'address@example.com';
text.linkify();

'http://stackoverflow.com/'.linkify();

Tak czy inaczej, oto skrypt:

if(!String.linkify) {
    String.prototype.linkify = function() {

        // http://, https://, ftp://
        var urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;

        // www. sans http:// or https://
        var pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;

        // Email addresses
        var emailAddressPattern = /[\w.]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim;

        return this
            .replace(urlPattern, '<a href="$&">$&</a>')
            .replace(pseudoUrlPattern, '$1<a href="http://$2">$2</a>')
            .replace(emailAddressPattern, '<a href="mailto:$&">$&</a>');
    };
}

Moim zdaniem najlepsze, ponieważ funkcje Prototype czynią rzeczy o wiele czystszymi :)
MRVDOG,

wygląda na to, że nie działa z takimi adresami e-mail: info@some-thing.com some.thing@example.com itp.
Marco Gagliardi

@MarcoGagliardi Dobry połów. Naprawiony.
Roshambo

1
To nie działa dla ciągu „git clone aaaa@bitbucket.org/ooo/bbb-cc-dd.git ”. Złamał ciąg na części i stworzył wiele takich kotwic, jak ten „git clone <a href="https://<a href="mailto:aaaa@bitbucket.org"> aaaa@bitbucket.org </a> / ooo / bbb-cc-dd.git "> https: // <a href="mailto:aaaa@bitbucket.org"> aaaa@bitbucket.org </a> /ooo/bbb-cc-dd.git </a> „
Jebin

1
Nie działa z +nazwami użytkowników poczty e-mail, takimi jak foo+bar@domain.com. Naprawiłem to za pomocą wzorca e-maila /[\w.+]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim(zwróć uwagę na +pierwsze nawiasy), ale nie wiem, czy to coś psuje.
dchacke

24

Dzięki, to było bardzo pomocne. Chciałem też czegoś, co łączyłoby rzeczy, które wyglądały jak adresy URL - jako podstawowy wymóg łączyłoby coś takiego jak www.yahoo.com, nawet jeśli prefiks protokołu http: // nie był obecny. Zasadniczo, jeśli „www”. jest obecny, połączy go i przyjmie, że to http: //. Chciałem też, aby wiadomości e-mail zamieniły się w mailto: linki. PRZYKŁAD: www.yahoo.com zostanie przekonwertowany na www.yahoo.com

Oto kod, na którym się skończyłem (kombinacja kodu z tej strony i innych rzeczy, które znalazłem online i innych rzeczy, które zrobiłem sam):

function Linkify(inputText) {
    //URLs starting with http://, https://, or ftp://
    var replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
    var replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');

    //URLs starting with www. (without // before it, or it'd re-link the ones done above)
    var replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    var replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');

    //Change email addresses to mailto:: links
    var replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim;
    var replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return replacedText
}

W drugim zastępowaniu część (^ | [^ /]) zastępuje www.whokolwiek.com tylko wtedy, gdy nie jest poprzedzona przedrostkiem // - aby uniknąć podwójnego linkowania, jeśli adres URL był już połączony przy pierwszej zamianie. Możliwe jest również, że www.whokolwiek.com może znajdować się na początku łańcucha, co jest pierwszym warunkiem „lub” w tej części wyrażenia regularnego.

Można to zintegrować jako wtyczkę jQuery, jak zilustrowano powyżej Jesse P. - ale szczególnie chciałem regularnej funkcji, która nie działałaby na istniejącym elemencie DOM, ponieważ pobieram tekst, który mam, a następnie dodam go do DOM, i Chcę, aby tekst był „linkified” przed dodaniem go, więc przekazuję tekst przez tę funkcję. Działa świetnie.


1
Wystąpił problem z drugim wzorcem, który sam pasuje do zwykłego „www.domain.com”. Problem występuje, gdy adres URL zawiera odsyłacz, na przykład: & location = http% 3A% 2F% 2Fwww.amazon.com% 2FNeil-Young% 2Fe% 2FB000APYJWA% 3Fqid% 3D1280679945% 26sr% 3D8-2-ent & tag = tra0c7 -20 & linkCode = ur2 & camp = 1789 & creative = 9325 - w takim przypadku link automatycznie się łączy. Szybką poprawką jest dodanie znaku „f” po zanegowanej liście zawierającej „/”. Tak więc wyrażenie brzmi: replacePattern2 = /(^|[^\/f])(www\.[\S]+(\b|$))/gim
Redtopia,

Powyższy kod nie przejdzie wielu testów przypadków skrajnych. Podczas wykrywania adresów URL lepiej polegać na specjalistycznej bibliotece. Oto dlaczego .
Dan Dascalescu

2
Właśnie uruchomiłem go na sznurku, w którym niektóre linki mają już na nich linki href. W takim przypadku nie psuje to istniejących działających linków.
AdamJones,

17

Identyfikacja adresów URL jest trudna, ponieważ często są otoczone znakami interpunkcyjnymi i ponieważ użytkownicy często nie używają pełnej formy adresu URL. Istnieje wiele funkcji JavaScript służących do zastępowania adresów URL hiperłączami, ale nie udało mi się znaleźć takiej, która działałaby tak dobrze, jak urlizefiltr w opartym na języku Python frameworku Django. Dlatego przeniosłem urlizefunkcję Django do JavaScript:

https://github.com/ljosa/urlize.js

Przykład:

urlize('Go to SO (stackoverflow.com) and ask. <grin>', 
       {nofollow: true, autoescape: true})
=> "Go to SO (<a href="http://stackoverflow.com" rel="nofollow">stackoverflow.com</a>) and ask. &lt;grin&gt;"

Drugi argument, jeśli jest prawdziwy, powoduje rel="nofollow"wstawienie. Trzeci argument, jeśli jest prawdziwy, unika znaków, które mają specjalne znaczenie w HTML. Zobacz plik README .


Działa również ze źródłem HTML, takim jak: www.web.com <a href = "https: // github. Com"> url </ a> trochę tekstu
Paulius Zaliaduonis

@Paulius: jeśli ustawisz opcję django_compatiblena false, to będzie trwać lepiej w przypadku użycia.
Vebjorn Ljosa

Django urlizenie obsługuje poprawnie TLD (przynajmniej nie port JS w GitHub). Biblioteką, która prawidłowo obsługuje TLD jest JavaScript Linkfy Ben Almana .
Dan Dascalescu

Dodano obsługę wykrywania adresów URL z dodatkowymi domenami najwyższego poziomu, nawet jeśli adres URL nie zaczyna się od „http” lub „www”.
Vebjorn Ljosa

10

Wprowadziłem zmianę w Roshambo String.linkify () w emailAddressPattern, aby rozpoznać adresy aaa.bbb. @ Ccc.ddd

if(!String.linkify) {
    String.prototype.linkify = function() {

        // http://, https://, ftp://
        var urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;

        // www. sans http:// or https://
        var pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;

        // Email addresses *** here I've changed the expression ***
        var emailAddressPattern = /(([a-zA-Z0-9_\-\.]+)@[a-zA-Z_]+?(?:\.[a-zA-Z]{2,6}))+/gim;

        return this
            .replace(urlPattern, '<a target="_blank" href="$&">$&</a>')
            .replace(pseudoUrlPattern, '$1<a target="_blank" href="http://$2">$2</a>')
            .replace(emailAddressPattern, '<a target="_blank" href="mailto:$1">$1</a>');
    };
}

Powyższy kod nie przejdzie wielu testów przypadków skrajnych. Podczas wykrywania adresów URL lepiej polegać na specjalistycznej bibliotece. Oto dlaczego .
Dan Dascalescu

9

Szukałem w Google czegoś nowego i natknąłem się na ten:

$('p').each(function(){
   $(this).html( $(this).html().replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '<a href="$1">$1</a> ') );
});

demo: http://jsfiddle.net/kachibito/hEgvc/1/

Działa naprawdę dobrze dla normalnych linków.


Co to są tutaj „Normalne linki”? Spójrz na rozwidlenie swojego dema tutaj: jsfiddle.net/hEgvc/27 Ludzie mogliby odkryć nie odkryte i uczynić to w łatwy sposób. Identyfikator URI nie jest rzeczą łatwą, jak na RFC3986, a jeśli chcesz objąć tylko „Normalne linki”, sugeruję, aby postępować zgodnie z tym wyrażeniem przynajmniej: ^ (([^: /? #] +):)? (// ([ ^ /? #] *))? ([^? #] *) (\? ([^ #] *))? (# (. *))?
Ivan

2
Miałem na myśli coś w formacie http://example.com/folder/folder/folder/lub https://example.org/blahetc - tylko typowy non-crazy format adresu URL, który będzie pasował do 95-99% przypadków użycia tam. Używam tego do wewnętrznego obszaru administracyjnego, więc nie potrzebuję niczego wymyślnego, aby złapać przypadkowe przypadki lub haslinki.
zdegenerowany


5

To rozwiązanie działa jak wiele innych i faktycznie używa tego samego wyrażenia regularnego co jedno z nich, jednak zamiast zwracania ciągu HTML zwróci fragment dokumentu zawierający element A i wszelkie odpowiednie węzły tekstowe.

 function make_link(string) {
    var words = string.split(' '),
        ret = document.createDocumentFragment();
    for (var i = 0, l = words.length; i < l; i++) {
        if (words[i].match(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi)) {
            var elm = document.createElement('a');
            elm.href = words[i];
            elm.textContent = words[i];
            if (ret.childNodes.length > 0) {
                ret.lastChild.textContent += ' ';
            }
            ret.appendChild(elm);
        } else {
            if (ret.lastChild && ret.lastChild.nodeType === 3) {
                ret.lastChild.textContent += ' ' + words[i];
            } else {
                ret.appendChild(document.createTextNode(' ' + words[i]));
            }
        }
    }
    return ret;
}

Istnieją pewne zastrzeżenia, a mianowicie ze starszą obsługą IE i textContent.

tutaj jest demo.


2
@DanDascalescu Zamiast głosowania kocem na dole, może podać swoje wspomniane przypadki krawędzi.
rlemon

Czy muszę? Spójrz na wyrażenie regularne składników dla adresów URL . Ale jeśli nalegasz, biegnij przeciwko pakietowi testowemu linkify Bena Almana . Zacząłem przyczyniać się do niepowodzenia testów, np. Do urlize , ale wkrótce zdałem sobie sprawę, że warto to robić tylko przy poważnych wysiłkach bibliotecznych. Z całym szacunkiem, powyższa jest odpowiedzią StackOverflow, a nie otwartą biblioteką próbującą poprawnie parsować adresy URL.
Dan Dascalescu

2
więc są przypadki na krawędziach. wspaniale. odpowiedzi te nadal mogą być przydatne dla innych, a ich ogólne głosowanie wydaje się przesadą. Inne odpowiedzi, które skomentowałeś i które najwyraźniej zostały odrzucone , zawierają przydatne informacje (a także twoją odpowiedź). nie wszyscy sprzeciwiają się wspomnianym sprawom i nie wszyscy będą chcieli korzystać z biblioteki.
rlemon

Dokładnie. Ci, którzy nie rozumieją ograniczeń wyrażeń regularnych, to ci, którzy z radością przejrzą pierwsze wyrażenie regularne od najbardziej uprzywilejowanej odpowiedzi i będą z nim biegać. To ludzie, którzy powinni najczęściej korzystać z bibliotek.
Dan Dascalescu

1
Ale jak to uzasadnienie, by nie głosować na każdą odpowiedź za pomocą wyrażenia regularnego, którego nie preferujesz?
rlemon

4

Jeśli chcesz pokazać krótszy link (tylko domenę), ale z tym samym długim adresem URL, możesz wypróbować moją modyfikację wersji kodu Sama Haslera opublikowanej powyżej

function replaceURLWithHTMLLinks(text) {
    var exp = /(\b(https?|ftp|file):\/\/([-A-Z0-9+&@#%?=~_|!:,.;]*)([-A-Z0-9+&@#%?\/=~_|!:,.;]*)[-A-Z0-9+&@#\/%=~_|])/ig;
    return text.replace(exp, "<a href='$1' target='_blank'>$3</a>");
}

3

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

function UriphiMe(text) {
      var exp = /(\b((https?|ftp|file):\/\/|(www))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]*)/ig; 
      return text.replace(exp,"<a href='$1'>$1</a>");
}

Poniżej kilka testowanych ciągów:

  1. Znajdź mnie na www.google.com
  2. www
  3. Znajdź mnie na www. http://www.com
  4. Śledź mnie na: http://www.nishantwork.wordpress.com
  5. http://www.nishantwork.wordpress.com
  6. Obserwuj mnie na : http://www.nishantwork.wordpress.com
  7. https://stackoverflow.com/users/430803/nishant

Uwaga: jeśli nie chcesz przekazać wwwpoprawnego, użyj poniższej opcji reg np: /(\b((https?|ftp|file):\/\/|(www))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig


Powyższy kod nie przejdzie wielu testów przypadków skrajnych. Podczas wykrywania adresów URL ZAWSZE lepiej polegać na specjalistycznej bibliotece. Oto dlaczego .
Dan Dascalescu

3

Należy zauważyć ostrzeżenia o złożoności URI, ale prosta odpowiedź na twoje pytanie brzmi:
aby zastąpić każde dopasowanie, musisz dodać /gflagę na końcu RegEx:
/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi


3
/**
 * Convert URLs in a string to anchor buttons
 * @param {!string} string
 * @returns {!string}
 */

function URLify(string){
  var urls = string.match(/(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)/g);
  if (urls) {
    urls.forEach(function (url) {
      string = string.replace(url, '<a target="_blank" href="' + url + '">' + url + "</a>");
    });
  }
  return string.replace("(", "<br/>(");
}

prosty przykład


2

Nie komplikuj! Powiedz to, czego nie możesz mieć, niż to, co możesz mieć :)

Jak wspomniano powyżej, adresy URL mogą być dość złożone, szczególnie po „?”, I nie wszystkie zaczynają się od „www”. na przykładmaps.bing.com/something?key=!"£$%^*()&lat=65&lon&lon=20

Więc zamiast skomplikowanego wyrażenia regularnego, które nie spełnia wszystkich przypadków brzegowych i będzie trudne do utrzymania, co powiesz na ten o wiele prostszy, który działa dobrze dla mnie w praktyce.

Mecz

http(s):// (anything but a space)+

www. (anything but a space)+

Gdzie „cokolwiek” jest [^'"<>\s] ... w zasadzie zachłannym dopasowaniem, kontynuowanie spotkania, cytatu, nawiasu kątowego lub końca linii

Również:

Pamiętaj, aby sprawdzić, czy nie jest już w formacie URL, np. Tekst zawiera href="..."lubsrc="..."

Dodaj ref = nofollow (w razie potrzeby)

To rozwiązanie nie jest tak „dobre” jak wspomniane powyżej biblioteki, ale jest znacznie prostsze i działa dobrze w praktyce.

if html.match( /(href)|(src)/i )) {
    return html; // text already has a hyper link in it
    }

html = html.replace( 
            /\b(https?:\/\/[^\s\(\)\'\"\<\>]+)/ig, 
            "<a ref='nofollow' href='$1'>$1</a>" 
            );

html = html.replace( 
            /\s(www\.[^\s\(\)\'\"\<\>]+)/ig, 
            "<a ref='nofollow' href='http://$1'>$1</a>" 
            );

html = html.replace( 
             /^(www\.[^\s\(\)\'\"\<\>]+)/ig, 
            "<a ref='nofollow' href='http://$1'>$1</a>" 
            );

return html;

2

Prawidłowe wykrywanie adresów URL z obsługą domen międzynarodowych i znaków astralnych nie jest trywialne. linkify-itbiblioteka buduje wyrażenia regularne z wielu warunków , a końcowy rozmiar to około 6 kilobajtów :). Jest dokładniejszy niż wszystkie biblioteki lib, obecnie przywoływane w zaakceptowanej odpowiedzi.

Zobacz linki demo-it aby sprawdzić na żywo wszystkie przypadki Edge i przetestować swoje.

Jeśli potrzebujesz linkować źródło HTML, powinieneś go najpierw przeanalizować i powtórzyć każdy token tekstowy osobno.



0

Musiałem zrobić coś przeciwnego i zrobić linki HTML tylko w adresie URL, ale zmodyfikowałem wyrażenie regularne i działa jak urok, dzięki :)

var exp = /<a\s.*href=['"](\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_ |!:,.;] * [- A-Z0-9 + & @ # \ /% = ~ _ |]) ['"]. *>. * <\ / A> / ig;

source = source.replace (exp, „$ 1”);

Nie widzę sensu twojego wyrażenia regularnego. Dopasowuje wszystko, zastępując wszystko wszystkim. W efekcie twój kod nic nie robi.
Chad Grant

8
Chyba powinienem poczekać na komentarz, aby umożliwić ludziom dokończenie edycji. Przepraszam.
Chad Grant

0

Wykrywanie wiadomości e-mail w powyższej odpowiedzi Travitrona nie działało dla mnie, więc rozszerzyłem / zastąpiłem go następującym kodem (kod C #).

// Change e-mail addresses to mailto: links.
const RegexOptions o = RegexOptions.Multiline | RegexOptions.IgnoreCase;
const string pat3 = @"([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,6})";
const string rep3 = @"<a href=""mailto:$1@$2.$3"">$1@$2.$3</a>";
text = Regex.Replace(text, pat3, rep3, o);

Pozwala to na adresy e-mail, takie jak „ imię.nazwisko@one.two.three.co.uk ”.


Powyższy kod nie przejdzie wielu testów przypadków skrajnych. Podczas wykrywania adresów URL ZAWSZE lepiej polegać na specjalistycznej bibliotece. Oto dlaczego .
Dan Dascalescu

Dzięki, @DanDascalescu Zwykle zawsze lepiej jest przesadnie uogólniać.
Uwe Keim

0

Po wejściu z kilku źródeł mam teraz rozwiązanie, które działa dobrze. Miało to związek z pisaniem własnego kodu zastępczego.

Odpowiedź .

Fiddle .

function replaceURLWithHTMLLinks(text) {
    var re = /(\(.*?)?\b((?:https?|ftp|file):\/\/[-a-z0-9+&@#\/%?=~_()|!:,.;]*[-a-z0-9+&@#\/%=~_()|])/ig;
    return text.replace(re, function(match, lParens, url) {
        var rParens = '';
        lParens = lParens || '';

        // Try to strip the same number of right parens from url
        // as there are left parens.  Here, lParenCounter must be
        // a RegExp object.  You cannot use a literal
        //     while (/\(/g.exec(lParens)) { ... }
        // because an object is needed to store the lastIndex state.
        var lParenCounter = /\(/g;
        while (lParenCounter.exec(lParens)) {
            var m;
            // We want m[1] to be greedy, unless a period precedes the
            // right parenthesis.  These tests cannot be simplified as
            //     /(.*)(\.?\).*)/.exec(url)
            // because if (.*) is greedy then \.? never gets a chance.
            if (m = /(.*)(\.\).*)/.exec(url) ||
                    /(.*)(\).*)/.exec(url)) {
                url = m[1];
                rParens = m[2] + rParens;
            }
        }
        return lParens + "<a href='" + url + "'>" + url + "</a>" + rParens;
    });
}

2
Powyższy kod (i większość wyrażeń regularnych w ogóle) nie przejdzie wielu testów dla przypadków krawędzi. Podczas wykrywania adresów URL lepiej polegać na specjalistycznej bibliotece. Oto dlaczego .
Dan Dascalescu

Dan, czy jest taka biblioteka? Chociaż w tym przypadku nadal będziemy dopasowywać powyższe wyrażenie regularne, aby kod nigdy nie wyrzucał śmieci, gdy coś takiego jak śmieci (nawet jeśli inna biblioteka potwierdza śmieci jako poprawny URL / URI) jest używane jako dane wejściowe.
Mike Mestnik


0

Oto moje rozwiązanie:

var content = "Visit https://wwww.google.com or watch this video: https://www.youtube.com/watch?v=0T4DQYgsazo and news at http://www.bbc.com";
content = replaceUrlsWithLinks(content, "http://");
content = replaceUrlsWithLinks(content, "https://");

function replaceUrlsWithLinks(content, protocol) {
    var startPos = 0;
    var s = 0;

    while (s < content.length) {
        startPos = content.indexOf(protocol, s);

        if (startPos < 0)
            return content;

        let endPos = content.indexOf(" ", startPos + 1);

        if (endPos < 0)
            endPos = content.length;

        let url = content.substr(startPos, endPos - startPos);

        if (url.endsWith(".") || url.endsWith("?") || url.endsWith(",")) {
            url = url.substr(0, url.length - 1);
            endPos--;
        }

        if (ROOTNS.utils.stringsHelper.validUrl(url)) {
            let link = "<a href='" + url + "'>" + url + "</a>";
            content = content.substr(0, startPos) + link + content.substr(endPos);
            s = startPos + link.length;
        } else {
            s = endPos + 1;
        }
    }

    return content;
}

function validUrl(url) {
    try {
        new URL(url);
        return true;
    } catch (e) {
        return false;
    }
}

0

Wypróbuj poniższą funkcję:

function anchorify(text){
  var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
  var text1=text.replace(exp, "<a href='$1'>$1</a>");
  var exp2 =/(^|[^\/])(www\.[\S]+(\b|$))/gim;
  return text1.replace(exp2, '$1<a target="_blank" href="http://$2">$2</a>');
}

alert(anchorify("Hola amigo! https://www.sharda.ac.in/academics/"));


0

Wypróbuj poniższe rozwiązanie

function replaceLinkClickableLink(url = '') {
let pattern = new RegExp('^(https?:\\/\\/)?'+
        '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+
        '((\\d{1,3}\\.){3}\\d{1,3}))'+
        '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+
        '(\\?[;&a-z\\d%_.~+=-]*)?'+
        '(\\#[-a-z\\d_]*)?$','i');

let isUrl = pattern.test(url);
if (isUrl) {
    return `<a href="${url}" target="_blank">${url}</a>`;
}
return url;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.