2009-09-30 65 views
94

¿Alguien tiene sugerencias para detectar URL en un conjunto de cadenas?Detectar URL en texto con JavaScript

arrayOfStrings.forEach(function(string){ 
    // detect URLs in strings and do something swell, 
    // like creating elements with links. 
}); 

Actualización: que terminaron el uso de esta expresión regular para la detección de enlace ... Al parecer, varios años más tarde.

kLINK_DETECTION_REGEX = /(([a-z]+:\/\/)?(([a-z0-9\-]+\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal))(:[0-9]{1,5})?(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(\s+|$)/gi 

El ayudante completo (con soporte opcional manillares) está en gist #1654670.

+7

Probablemente no sea una buena idea para tratar de hacer una lista de un conjunto finito de TLD, ya que siguen creando otros nuevos. –

+0

De acuerdo. A veces necesitamos un código de actualización con TLD. En realidad, puede ser script de compilación para agregar TLD a los TLD de actualización de código dinámico o regex en el código. Hay cosas en la vida que significan estandarizarse como TLD y Timezone. El control finito podría ser bueno para verificar el URL verificable de "TLDs" existentes para el caso de uso de la dirección Real World. –

Respuesta

135

Primero necesitas una buena expresión regular que coincida con las URL. Esto es difícil de hacer Ver here, here y here:

... casi cualquier cosa es una URL válida. Hay son algunas reglas de puntuación para dividirlo. Ausente cualquier puntuación , aún tiene una URL válida.

Compruebe la RFC detenidamente y vea si puede construir una URL "no válida". Las reglas son muy flexibles.

Por ejemplo, ::::: es una URL válida. La ruta es ":::::". Un bonito nombre de archivo estúpido , pero un nombre de archivo válido.

Además, ///// es una URL válida. El netloc ("nombre de host") es "". La ruta es "///". De nuevo, estúpido. También válido. Esta URL se normaliza a "///" , que es el equivalente.

Algo así como "bad://///worse/////" es perfectamente válido. Tonto pero válido

De todos modos, esta respuesta no pretende brindarle la mejor expresión regular, sino más bien una prueba de cómo hacer la envoltura de cadenas dentro del texto, con JavaScript.

OK así que solo utilice éste: /(https?:\/\/[^\s]+)/g

Una vez más, esto es una mala expresión regular. Tendrá muchos falsos positivos. Sin embargo, es lo suficientemente bueno para este ejemplo.

function urlify(text) { 
    var urlRegex = /(https?:\/\/[^\s]+)/g; 
    return text.replace(urlRegex, function(url) { 
     return '<a href="' + url + '">' + url + '</a>'; 
    }) 
    // or alternatively 
    // return text.replace(urlRegex, '<a href="$1">$1</a>') 
} 

var text = "Find me at http://www.example.com and also at http://stackoverflow.com"; 
var html = urlify(text); 

// html now looks like: 
// "Find me at <a href="http://www.example.com">http://www.example.com</a> and also at <a href="http://stackoverflow.com">http://stackoverflow.com</a>" 

Así pues, en suma intento:

$$('#pad dl dd').each(function(element) { 
    element.innerHTML = urlify(element.innerHTML); 
}); 
+0

Genial: exactamente lo que estaba buscando. RexExp siempre ha estado más allá de mí. – arbales

+2

Algunos ejemplos de "muchos falsos positivos" mejorarían en gran medida esta respuesta. De lo contrario, los futuros Googlers quedarán con algo (tal vez válido) FUD. – cmcculloh

+0

Nunca supe que puede pasar la función como segundo parámetro para '' '.replace''': | –

84

Esto es lo que terminé usando como mi expresión regular:

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

Esto no incluye detrás de puntuacion en la URL.La función de la Media Luna funciona como un encanto :) manera:

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

¡Finalmente una expresión regular que realmente funciona en el caso más obvio! Este merece un marcador. Probé miles de ejemplos desde la búsqueda de Google hasta que encuentro esto. – Ismael

+2

¡Simple y agradable! Pero el 'urlRegex' debe definirse _outside_' linkify' ya que su compilación es cara. –

+0

Esto no detecta la URL completa: http://disney.wikia.com/wiki/Pua_(Moana) – Jry9972

5

función puede mejorarse aún más para representar imágenes así:

function renderHTML(text) { 
    var rawText = strip(text) 
    var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 

    return rawText.replace(urlRegex, function(url) { 

    if ((url.indexOf(".jpg") > 0) || (url.indexOf(".png") > 0) || (url.indexOf(".gif") > 0)) { 
      return '<img src="' + url + '">' + '<br/>' 
     } else { 
      return '<a href="' + url + '">' + url + '</a>' + '<br/>' 
     } 
    }) 
} 

o una imagen en miniatura que se vincula a fiull la imagen a tamaño para:

return '<a href="' + url + '"><img style="width: 100px; border: 0px; -moz-border-radius: 5px; border-radius: 5px;" src="' + url + '">' + '</a>' + '<br/>' 

Y aquí está la función strip() que preprocesa la cadena de texto para uniformidad mediante la eliminación de cualquier html existente.

function strip(html) 
    { 
     var tmp = document.createElement("DIV"); 
     tmp.innerHTML = html; 
     var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 
     return tmp.innerText.replace(urlRegex, function(url) {  
     return '\n' + url 
    }) 
} 
+0

cuando publico www.google.com, no está detectando –

35

Busqué en Google este problema durante bastante tiempo, entonces se me ocurrió que no hay un método Android, android.text.util.Linkify, que utiliza algunas expresiones regulares bastante robustos para lograr esto. Afortunadamente, Android es de código abierto.

Utilizan algunos patrones diferentes para unir diferentes tipos de urls. Usted puede encontrar todos aquí: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.0_r1/android/text/util/Regex.java#Regex.0WEB_URL_PATTERN

Si no eres más que preocupados por la URL que coinciden con el WEB_URL_PATTERN, es decir, las direcciones URL que se ajustan a la especificación RFC 1738, puede utilizar esta:

/((?:(http|https|Http|Https|rtsp|Rtsp):\/\/(?:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,64}(?:\:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,25})?\@)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\:\d{1,5})?)(\/(?:(?:[a-zA-Z0-9\;\/\?\:\@\&\=\#\~\-\.\+\!\*\'\(\)\,\_])|(?:\%[a-fA-F0-9]{2}))*)?(?:\b|$)/gi; 

aquí está el texto completo de la fuente:

"((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" 
+ "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" 
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" 
+ "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host 
+ "(?:" // plus top level domain 
+ "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])" 
+ "|(?:biz|b[abdefghijmnorstvwyz])" 
+ "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])" 
+ "|d[ejkmoz]" 
+ "|(?:edu|e[cegrstu])" 
+ "|f[ijkmor]" 
+ "|(?:gov|g[abdefghilmnpqrstuwy])" 
+ "|h[kmnrtu]" 
+ "|(?:info|int|i[delmnoqrst])" 
+ "|(?:jobs|j[emop])" 
+ "|k[eghimnrwyz]" 
+ "|l[abcikrstuvy]" 
+ "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])" 
+ "|(?:name|net|n[acefgilopruz])" 
+ "|(?:org|om)" 
+ "|(?:pro|p[aefghklmnrstwy])" 
+ "|qa" 
+ "|r[eouw]" 
+ "|s[abcdeghijklmnortuvyz]" 
+ "|(?:tel|travel|t[cdfghjklmnoprtvwz])" 
+ "|u[agkmsyz]" 
+ "|v[aceginu]" 
+ "|w[fs]" 
+ "|y[etu]" 
+ "|z[amw]))" 
+ "|(?:(?:25[0-5]|2[0-4]" // or ip address 
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]" 
+ "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]" 
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" 
+ "|[1-9][0-9]|[0-9])))" 
+ "(?:\\:\\d{1,5})?)" // plus option port number 
+ "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params 
+ "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" 
+ "(?:\\b|$)"; 

Si quieres ser realmente de lujo, puede validar direcciones de correo electrónico también. La expresión regular para las direcciones de correo electrónico es:

/[a-zA-Z0-9\\+\\.\\_\\%\\-]{1,256}\\@[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+/gi 

PS: Los dominios de nivel superior con el apoyo de expresión regular anterior han sido actualizadas en junio de 2007. Para una lista actualizada que necesita para comprobar https://data.iana.org/TLD/tlds-alpha-by-domain.txt.

+1

Como tiene una expresión regular que no distingue entre mayúsculas y minúsculas, no es necesario especificar 'a-zA-Z' y' http | https | Http | Https | rtsp | Rtsp'. – Ryan

+0

RFC 1738 no coincide con el enlace http://t.co/500S3LZpWA – Ismael

+2

Esto es bueno, pero no estoy seguro de que alguna vez lo use. Para la mayoría de los casos de uso, preferiría aceptar algunos falsos positivos que utilizar un enfoque que se base en una lista de TLD rígida. Si incluye los TLD en su código, está garantizando que algún día estará obsoleto, y prefiero no crear mantenimiento futuro obligatorio en mi código si puedo evitarlo. –

1

tmp.innerTexto no está definido. Debe utilizar tmp.innerHTML

function strip(html) 
    { 
     var tmp = document.createElement("DIV"); 
     tmp.innerHTML = html; 
     var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 
     return tmp.innerHTML .replace(urlRegex, function(url) {  
     return '\n' + url 
    }) 
14

Sobre la base de la Media Luna fresco respuesta

si desea detectar enlaces con http: // O sin http: // www y. puede utilizar el siguiente

function urlify(text) { 
    var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g; 
    //var urlRegex = /(https?:\/\/[^\s]+)/g; 
    return text.replace(urlRegex, function(url,b,c) { 
     var url2 = (c == 'www.') ? 'http://' +url : url; 
     return '<a href="' +url2+ '" target="_blank">' + url + '</a>'; 
    }) 
} 
2

Esta biblioteca en busca NGP como es bastante completa https://www.npmjs.com/package/linkifyjs

Linkify es un pequeño plugin pero completa JavaScript para encontrar las direcciones URL en texto plano y su conversión a HTML campo de golf. Funciona con todas las URL y direcciones de correo electrónico válidas.

+0

Acabo de terminar la implementación de linkifyjs en mi proyecto y es fantástico. Linkifyjs debería ser la respuesta a esta pregunta. El otro para mirar es https://github.com/twitter/twitter-text –

0

probar esto:

function isUrl(s) { 
    if (!isUrl.rx_url) { 
     // taken from https://gist.github.com/dperini/729294 
     isUrl.rx_url=/^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)[email protected])?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|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]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i; 
     // valid prefixes 
     isUrl.prefixes=['http:\/\/', 'https:\/\/', 'ftp:\/\/', 'www.']; 
     // taken from https://w3techs.com/technologies/overview/top_level_domain/all 
     isUrl.domains=['com','ru','net','org','de','jp','uk','br','pl','in','it','fr','au','info','nl','ir','cn','es','cz','kr','ua','ca','eu','biz','za','gr','co','ro','se','tw','mx','vn','tr','ch','hu','at','be','dk','tv','me','ar','no','us','sk','xyz','fi','id','cl','by','nz','il','ie','pt','kz','io','my','lt','hk','cc','sg','edu','pk','su','bg','th','top','lv','hr','pe','club','rs','ae','az','si','ph','pro','ng','tk','ee','asia','mobi']; 
    } 

    if (!isUrl.rx_url.test(s)) return false; 
    for (let i=0; i<isUrl.prefixes.length; i++) if (s.startsWith(isUrl.prefixes[i])) return true; 
    for (let i=0; i<isUrl.domains.length; i++) if (s.endsWith('.'+isUrl.domains[i]) || s.includes('.'+isUrl.domains[i]+'\/') ||s.includes('.'+isUrl.domains[i]+'?')) return true; 
    return false; 
} 

function isEmail(s) { 
    if (!isEmail.rx_email) { 
     // taken from http://stackoverflow.com/a/16016476/460084 
     var sQtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'; 
     var sDtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'; 
     var sAtom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'; 
     var sQuotedPair = '\\x5c[\\x00-\\x7f]'; 
     var sDomainLiteral = '\\x5b(' + sDtext + '|' + sQuotedPair + ')*\\x5d'; 
     var sQuotedString = '\\x22(' + sQtext + '|' + sQuotedPair + ')*\\x22'; 
     var sDomain_ref = sAtom; 
     var sSubDomain = '(' + sDomain_ref + '|' + sDomainLiteral + ')'; 
     var sWord = '(' + sAtom + '|' + sQuotedString + ')'; 
     var sDomain = sSubDomain + '(\\x2e' + sSubDomain + ')*'; 
     var sLocalPart = sWord + '(\\x2e' + sWord + ')*'; 
     var sAddrSpec = sLocalPart + '\\x40' + sDomain; // complete RFC822 email address spec 
     var sValidEmail = '^' + sAddrSpec + '$'; // as whole string 

     isEmail.rx_email = new RegExp(sValidEmail); 
    } 

    return isEmail.rx_email.test(s); 
} 

se reconocen también las direcciones URL como google.com, http://www.google.bla, http://google.bla, www.google.bla pero no google.bla