Compruebe si una cadena de JavaScript es una URL


284

¿Hay alguna manera en JavaScript para verificar si una cadena es una URL?

Las RegExes están excluidas porque la URL probablemente está escrita como stackoverflow; es decir que podría no tener un .com, wwwo http.


22
Si le falta http, por defecto no hay url.
nfechner

1
@nfechner, es decir, si no especifica un protocolo y usa el carácter de dos puntos (preferiblemente con dos barras inclinadas a continuación), ¿entonces no es una URL?
jcolebrand

55
Como puede leer en el RFC de URL , la única parte realmente necesaria para hacer que un String sea un URL válido es los dos puntos. Las URL válidas se ven así:<scheme>:<scheme-specific-part>
nfechner


8
La forma en que se prueba si algo es una URL depende en gran medida del contexto y es demasiado vaga sin calificación adicional. ¿Le importa si se ajusta a la especificación de RFC de URL, funciona cuando se realiza una llamada al sistema operativo para abrir la URL , se analiza como un hrefelemento de anclaje, funciona al llamar window.open(url), señala algo que realmente existe, funciona en la ubicación del navegador barra, o una combinación de lo anterior? Obtendrá respuestas muy diferentes según cuál de estas le interese.
Roy Tinker

Respuestas:


189

Una pregunta relacionada con una respuesta:

Javascript regex coincidencia de URL

O este Regexp de Devshed :

function validURL(str) {
  var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
    '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
    '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
    '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
    '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
    '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  return !!pattern.test(str);
}

1
Lo sé, pero estoy buscando en mis marcadores y la mayoría de ellos están escritos como stackoverflow (sin .com, etc.)
Bruno

44
@Bruno: es muy probable que se guarden internamente con títulos y URL separados, como { title: "Stackoverflow", uri: "http://stackoverflow.com" } Actualización: de hecho, consulte code.google.com/chrome/extensions/bookmarks.html
Marcel Korpel

10
tratando de usar tu ejemplo. Pero recibo un error en firebug que dice invalid quantifier. ¿Alguna idea?
Sisir

125
Función devuelta: SyntaxError: Invalid regular expression: /^(https?://)?((([a-zd]([a-zd-]*[a-zd])*).)+[a-z]{2,}|((d{1,3}.){3}d{1,3}))(:d+)?(/[-a-zd%_.~+]*)*(?[;&a-zd%_.~+=-]*)?(#[-a-zd_]*)?$/: Invalid group Google Chrome (versión 30.0.1599.101) (Mac OS X: 10.8.5)
dr.dimitru

10
Tenga en cuenta que si utiliza una cadena como parámetro RegExp, debe escapar dos veces de las barras invertidas; de lo contrario, obtendrá errores como un grupo no válido .
Kjell

165
function isURL(str) {
  var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
  '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+ // domain name
  '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
  '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
  '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
  '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  return pattern.test(str);
}

13
falla para los enlaces de imágenes de búsqueda de Google:http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707
bill davis

77
esto es inutilizable lento
Hernán Eche

3
@ HernánEche ¿Qué quieres decir con lento ? start = new Date(); isURL("http://michalstefanow.com"); end = new Date(); diff = end - start; console.log(diff)Puse una caldera, fui a un inodoro, llamé a mi madre y la cosa se hizo en ningún momento ...
Marte Robertson

62
Vuelve truepor aaa.
alex naumov

1
Esta no debería ser la respuesta correcta. Falla en muchos casos de prueba y, lo que es más importante, cuelga su página incluso en una cadena corta: isURL('12345678901234567890123')agregue algunos caracteres más y es aún peor.
aamarks

142

Puede intentar usar el URLconstructor : si no se lanza, la cadena es una URL válida:

function isValidUrl(string) {
  try {
    new URL(string);
  } catch (_) {
    return false;  
  }

  return true;
}

El término 'URL' se define en RFC 3886 (como URI); debe comenzar con un nombre de esquema, y ​​el nombre del esquema no está limitado a http / https.

Ejemplos notables:

  • www.google.com no es URL válida (esquema faltante)
  • javascript:void(0) es una URL válida, aunque no una HTTP
  • http://..Es URL válida, con el anfitrión bienestar ..; si se resuelve depende de su DNS
  • https://google..com es una URL válida, igual que la anterior

Si desea verificar si una cadena es una URL HTTP válida:

function isValidHttpUrl(string) {
  let url;

  try {
    url = new URL(string);
  } catch (_) {
    return false;  
  }

  return url.protocol === "http:" || url.protocol === "https:";
}

13
@AshD no, no lo es; por ejemplo, no se puede usar como hrefatributo para <a>. La URL válida debe comenzar con un nombre de esquema , por ejemplo https://.
Pavlo

3
nueva URL ('javascript: alert (23)')
blade091

66
@Pavlo esto vuelve verdaderoisValidUrl("javascript:void(0)")
Praveena

3
Me gusta esto por enseñarme cosas nuevas sobre js! No tiene falsos negativos que pude encontrar. Tiene algunos falsos positivos: http://..Ohttp:///a
aamarks

2
La URL funciona a partir de Edge, por lo que todo lo que está debajo puede no funcionar como espera. Asegúrese de verificar primero la compatibilidad.
Tony T.

97

En lugar de usar una expresión regular, recomendaría usar un elemento de anclaje.

cuando establece la hrefpropiedad de un anchor, se establecen varias otras propiedades.

var parser = document.createElement('a');
parser.href = "http://example.com:3000/pathname/?search=test#hash";

parser.protocol; // => "http:"
parser.hostname; // => "example.com"
parser.port;     // => "3000"
parser.pathname; // => "/pathname/"
parser.search;   // => "?search=test"
parser.hash;     // => "#hash"
parser.host;     // => "example.com:3000"

fuente

Sin embargo, si el valor al que hrefestá vinculado no es una URL válida, entonces el valor de esas propiedades auxiliares será la cadena vacía.

Editar: como se señala en los comentarios: si se usa una URL no válida, las propiedades de la URL actual pueden ser sustituidas.

Por lo tanto, siempre que no pase la URL de la página actual, puede hacer algo como:

function isValidURL(str) {
   var a  = document.createElement('a');
   a.href = str;
   return (a.host && a.host != window.location.host);
}

3
Este no es el caso (en Chrome 48 al menos). Si la URL pasada a.hrefno es válida, parser.hostdevuelve el nombre de host de la página en la que se encuentra actualmente, no el esperado false.
Sam Beckham

2
Gah! eso es raro. ¡Juro que probé esto! Creo que es justo decir que esto realmente nunca tendrá que usarse en la página actual, por lo que el condicional solo se puede cambiar. Editaré la publicación.
Lucas

no es un caso de uso muy típico, pero esta técnica no funciona en el contexto de la ventana del navegador Firefox (importante para el desarrollo de complementos)
chrmod

@SamBeckham Esto definitivamente es una preocupación al usar este método, pero solo quiero señalar que este no es un comportamiento especial. Si usted tiene un enlace en su página que es inválida, como <a href="invalidurl">, que no vaya a su dominio. Se agrega al final de la url actual. Entonces Chrome está haciendo lo correcto al darle el nombre de host actual del elemento "analizador".
yts

44
function isValidURL(str): mucho mejor que usar regex! ¡Gracias!
Rodrigo

47

Estoy usando la siguiente función para validar URL con o sin http/https:

function isValidURL(string) {
  var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
  return (res !== null)
};

var testCase1 = "http://en.wikipedia.org/wiki/Procter_&_Gamble";
console.log(isValidURL(testCase1)); // return true

var testCase2 = "http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707";
console.log(isValidURL(testCase2)); // return true

var testCase3 = "https://sdfasd";
console.log(isValidURL(testCase3)); // return false

var testCase4 = "dfdsfdsfdfdsfsdfs";
console.log(isValidURL(testCase4)); // return false

var testCase5 = "magnet:?xt=urn:btih:123";
console.log(isValidURL(testCase5)); // return false

var testCase6 = "https://stackoverflow.com/";
console.log(isValidURL(testCase6)); // return true

var testCase7 = "https://w";
console.log(isValidURL(testCase7)); // return false

var testCase8 = "https://sdfasdp.ppppppppppp";
console.log(isValidURL(testCase8)); // return false


2
Parece una buena solución! ¿Podría agregar algunas pruebas que muestren que funciona en algunos casos de esquina (ver, por ejemplo, estos comentarios )?
Basj

@Basj agregó casos de prueba. Por favor verifique
Vikasdeep Singh

No está mal, no pasa http: //⌘.ws o 142.42.1.1 y permite http: //.www.foo.bar./ pero no se cuelga como algunas de las otras expresiones regulares, incluidas las respuestas mejor calificadas.
aamarks

@aamarks Verifiqué tu respuesta. Tu respuesta falla, es https://sdfasdp.pppppppppppdecir, regresar, truepero la mía regresa, lo falseque se espera, creo.
Vikasdeep Singh

44
está volviendo cierto para sadf@gmail.com... ¿debería? Supongo que no debería
Zohab Ali

35

Para validar la URL usando javascript se muestra a continuación

function ValidURL(str) {
  var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
  if(!regex .test(str)) {
    alert("Please enter valid URL.");
    return false;
  } else {
    return true;
  }
}

3
Varias partes de la expresión regular podrían reducirse enormemente: a) (http|https)a (?:https?); b) :{0,1}a :?; c) [0-9]a\d
Dmitry Parzhitsky


23

Mejora en la respuesta aceptada ...

  • Verificar ftp / ftps como protocolo
  • Tiene doble escape para barras invertidas (\\)
  • Asegura que los dominios tengan un punto y una extensión (.com .io .xyz)
  • Permite dos puntos (:) en la ruta, por ejemplo, http://thingiverse.com/download:1894343
  • Permite ampersand (&) en la ruta, por ejemplo, http://en.wikipedia.org/wiki/Procter_&_Gamble
  • Permite el símbolo @ en la ruta, por ejemplo, https://medium.com/@techytimo

    isURL(str) {
      var pattern = new RegExp('^((ft|htt)ps?:\\/\\/)?'+ // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name and extension
      '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
      '(\\:\\d+)?'+ // port
      '(\\/[-a-z\\d%@_.~+&:]*)*'+ // path
      '(\\?[;&a-z\\d%@_.,~+&:=-]*)?'+ // query string
      '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
      return pattern.test(str);
    }

55
No, no debería ser la respuesta aceptada. Al igual que algunos de los otros, se cuelga en una mera cadena de 33 caracteres: isURL ('123456789012345678901234567890123') y falla muchas pruebas de casos de borde: foo.com/blah_blah_(wikipedia)_(aiki) // devuelve incorrectamente falso.
aamarks

2
Esto se debe a que localhost: 8080 no es una URL válida.
Shane


Debe ser ftps: // localhost: 8080 =)
vp_arth

No parece funcionar: se cuelga de una entrada larga (como dijo @aanmarks)
cecemel

13

Aquí hay otro método más.

var elm;
function isValidURL(u){
  if(!elm){
    elm = document.createElement('input');
    elm.setAttribute('type', 'url');
  }
  elm.value = u;
  return elm.validity.valid;
}

console.log(isValidURL('http://www.google.com/'));
console.log(isValidURL('//google.com'));
console.log(isValidURL('google.com'));
console.log(isValidURL('localhost:8000'));


Código educativo! El mecanismo aquí es probablemente idéntico a cómo funciona new URL(string)el código de Pavlo. Ambas pruebas tienen resultados idénticos con todos los casos límite que probé. Me gusta su código porque es más simple y no implica la creación de elementos, pero el tuyo es varias veces más rápido (probablemente porque no crea el el después del primer uso).
aamarks

1
¡Gracias! Implementé tu consejo. Sin embargo, tenga en cuenta: los navegadores antiguos y / o WebView de dispositivos móviles pueden no haber implementado el elemento <input type = url>; por lo tanto, el valor de entrada se trataría como un texto normal (sin validación de URL). REF: developer.mozilla.org/en-US/docs/Web/HTML/Element/input/url
Panini Luncher

10

(No tengo representantes para comentar sobre el ejemplo de ValidURL ; por lo tanto, publique esto como respuesta).

Aunque no se recomienda el uso de protocolos URL relativas ( La dirección URL relativa al protocolo ), lo hacen llegar emplean a veces. Para validar dicha URL con una expresión regular, la parte del protocolo podría ser opcional, por ejemplo:

function isValidURL(str) {
    var pattern = new RegExp('^((https?:)?\\/\\/)?'+ // protocol
        '(?:\\S+(?::\\S*)?@)?' + // authentication
        '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
        '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
        '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
        '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
        '(\\#[-a-z\\d_]*)?$','i'); // fragment locater
    if (!pattern.test(str)) {
        return false;
    } else {
        return true;
    }
}

Sin embargo, como otros señalaron, la expresión regular no parece ser el enfoque más adecuado para validar URL.


Al principio pensé que esto era bastante bueno, pero falló muchas de las pruebas en mathiasbynens.be/demo/url-regex , y luego se isValidURL("https://d1f4470da51b49289906b3d6cbd65074@app.getsentry.com/13176")
aferra

Sí, como dije, simplemente comenté la parte del protocolo. Agregué la cláusula de autenticación para manejar @. No cuelga en mis navegadores .
ko la

Lo siento, estaba revisando varios de estos para evaluarlos y me perdí que el tuyo estaba comentando la respuesta dada. Creo que su corrección incluso me ayudó a comenzar con esto cuando visité esta página por primera vez. No colgando ahora.
aamarks

9

Puede usar la API nativa de URL :

  const isUrl = string => {
      try { return Boolean(new URL(string)); }
      catch(e){ return false; }
  }

3
Se ve muy similar a la respuesta proporcionada por @pavlo, solo se cambiaron los nombres de las variables;)
Munim Munna

2
Realmente debería haber un método nativo simple para verificar esto por ahora: esta respuesta parecía muy prometedora, pero vuelve a ser cierta tan pronto como @Basj mencionó anteriormente.
zero_cool

8

Como se ha señalado, la expresión regular perfecta es difícil de alcanzar pero parece ser un enfoque razonable (las alternativas son pruebas del lado del servidor o la nueva API de URL experimental ). Sin embargo, las respuestas de alto rango a menudo devuelven falsas para las URL comunes, pero aún peor congelarán su aplicación / página durante minutos en una cadena tan simple como isURL('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'). Se ha señalado en algunos de los comentarios, pero lo más probable es que no haya ingresado un valor malo para verlo. Colgar así hace que ese código sea inutilizable en cualquier aplicación seria. Creo que se debe a los conjuntos de mayúsculas y minúsculas repetidas en código como ((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|' .... Saque la 'i' y no se cuelga, pero por supuesto no funcionará como se desea. Pero incluso con el indicador de ignorar mayúsculas y minúsculas, esas pruebas rechazan valores altos de Unicode que están permitidos.

Lo mejor ya mencionado es:

function isURL(str) {
  return /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(str); 
}

Eso viene de Github segmento / is-url . Lo bueno de un repositorio de código es que puede ver las pruebas y cualquier problema y también las cadenas de prueba que se ejecutan a través de él. Hay una rama que permitiría que falten cadenas como el protocolo google.com, aunque probablemente estés haciendo demasiados supuestos en ese momento. El repositorio se ha actualizado y no planeo tratar de mantener un espejo aquí. Se ha dividido en pruebas separadas para evitar rehacer RegEx que pueden explotarse para ataques DOS (no creo que tenga que preocuparse por eso con el lado del cliente js, pero sí tiene que preocuparse de que su página se cuelgue durante tanto tiempo que su el visitante abandona tu sitio).

Hay otro repositorio que he visto que puede ser incluso mejor para isURL en dperini / regex-weburl.js , pero es muy complejo. Tiene una lista de prueba más grande de URL válidas e inválidas. El simple anterior todavía pasa todos los positivos y solo falla al bloquear algunos negativos negativos http://a.b--c.de/, así como los ips especiales.

Cualquiera que elija, ejecútelo a través de esta función que he adaptado de las pruebas en dperini / regex-weburl.js, mientras utiliza el inpector Herramientas de desarrollo de su navegador.

function testIsURL() {
//should match
console.assert(isURL("http://foo.com/blah_blah"));
console.assert(isURL("http://foo.com/blah_blah/"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)_(again)"));
console.assert(isURL("http://www.example.com/wpstyle/?p=364"));
console.assert(isURL("https://www.example.com/foo/?bar=baz&inga=42&quux"));
console.assert(isURL("http://✪df.ws/123"));
console.assert(isURL("http://userid:password@example.com:8080"));
console.assert(isURL("http://userid:password@example.com:8080/"));
console.assert(isURL("http://userid@example.com"));
console.assert(isURL("http://userid@example.com/"));
console.assert(isURL("http://userid@example.com:8080"));
console.assert(isURL("http://userid@example.com:8080/"));
console.assert(isURL("http://userid:password@example.com"));
console.assert(isURL("http://userid:password@example.com/"));
console.assert(isURL("http://142.42.1.1/"));
console.assert(isURL("http://142.42.1.1:8080/"));
console.assert(isURL("http://➡.ws/䨹"));
console.assert(isURL("http://⌘.ws"));
console.assert(isURL("http://⌘.ws/"));
console.assert(isURL("http://foo.com/blah_(wikipedia)#cite-1"));
console.assert(isURL("http://foo.com/blah_(wikipedia)_blah#cite-1"));
console.assert(isURL("http://foo.com/unicode_(✪)_in_parens"));
console.assert(isURL("http://foo.com/(something)?after=parens"));
console.assert(isURL("http://☺.damowmow.com/"));
console.assert(isURL("http://code.google.com/events/#&product=browser"));
console.assert(isURL("http://j.mp"));
console.assert(isURL("ftp://foo.bar/baz"));
console.assert(isURL("http://foo.bar/?q=Test%20URL-encoded%20stuff"));
console.assert(isURL("http://مثال.إختبار"));
console.assert(isURL("http://例子.测试"));
console.assert(isURL("http://उदाहरण.परीक्षा"));
console.assert(isURL("http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com"));
console.assert(isURL("http://1337.net"));
console.assert(isURL("http://a.b-c.de"));
console.assert(isURL("http://223.255.255.254"));
console.assert(isURL("postgres://u:p@example.com:5702/db"));
console.assert(isURL("https://d1f4470da51b49289906b3d6cbd65074@app.getsentry.com/13176"));

//SHOULD NOT MATCH:
console.assert(!isURL("http://"));
console.assert(!isURL("http://."));
console.assert(!isURL("http://.."));
console.assert(!isURL("http://../"));
console.assert(!isURL("http://?"));
console.assert(!isURL("http://??"));
console.assert(!isURL("http://??/"));
console.assert(!isURL("http://#"));
console.assert(!isURL("http://##"));
console.assert(!isURL("http://##/"));
console.assert(!isURL("http://foo.bar?q=Spaces should be encoded"));
console.assert(!isURL("//"));
console.assert(!isURL("//a"));
console.assert(!isURL("///a"));
console.assert(!isURL("///"));
console.assert(!isURL("http:///a"));
console.assert(!isURL("foo.com"));
console.assert(!isURL("rdar://1234"));
console.assert(!isURL("h://test"));
console.assert(!isURL("http:// shouldfail.com"));
console.assert(!isURL(":// should fail"));
console.assert(!isURL("http://foo.bar/foo(bar)baz quux"));
console.assert(!isURL("ftps://foo.bar/"));
console.assert(!isURL("http://-error-.invalid/"));
console.assert(!isURL("http://a.b--c.de/"));
console.assert(!isURL("http://-a.b.co"));
console.assert(!isURL("http://a.b-.co"));
console.assert(!isURL("http://0.0.0.0"));
console.assert(!isURL("http://10.1.1.0"));
console.assert(!isURL("http://10.1.1.255"));
console.assert(!isURL("http://224.1.1.1"));
console.assert(!isURL("http://1.1.1.1.1"));
console.assert(!isURL("http://123.123.123"));
console.assert(!isURL("http://3628126748"));
console.assert(!isURL("http://.www.foo.bar/"));
console.assert(!isURL("http://www.foo.bar./"));
console.assert(!isURL("http://.www.foo.bar./"));
console.assert(!isURL("http://10.1.1.1"));}

Y luego prueba esa cadena de 'a's.

Consulte esta comparación de expresiones regulares isURL de Mathias Bynens para obtener más información antes de publicar una expresión regular aparentemente excelente.


Revisé tu respuesta. Su respuesta falla para sdfasdp.ppppppppppp, es decir, devolver verdadero pero se espera que sea falso
Vikasdeep Singh

1
Creo que es una URL válida, estructuralmente. No soy un experto en el estándar, pero no creo que haya un límite en la longitud de la parte .com (sé que .online es legítimo).
aamarks

1
Apenas sabía cómo escribir una expresión regular hace un par de meses. El problema es severo. Tanto la expresión regular que cité puede completar isURL('a'.repeat(100))millones de veces / segundo (la más compleja de dperini es en realidad más rápida). Algunas de las respuestas de alto rango del formulario ([a-zA-Z] +) * tardarían horas en completarse una vez. Busque redo RegEx para más información.
aamarks

6

No puedo comentar sobre la publicación que es la más cercana # 5717133 , pero a continuación es la forma en que descubrí cómo hacer que @ tom-gullen regex funcione.

/^(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

2
Esto funcionó para mí, pero necesitaba reducir la barra diagonal inversa. var 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');
Fernando Chavez Herrera

Visite w3resource.com/javascript-exercises/… para más casos de prueba
Kewal Shah

5

Use validator.js

ES6

import isURL from 'validator/lib/isURL'

isURL(string)

No ES6

var validator = require('validator');

validator.isURL(string)

También puede ajustar el comportamiento de esta función pasando un optionsobjeto opcional como el segundo argumento deisURL

Aquí está el optionsobjeto predeterminado :

let options = {
    protocols: [
        'http',
        'https',
        'ftp'
    ],
    require_tld: true,
    require_protocol: false,
    require_host: true,
    require_valid_protocol: true,
    allow_underscores: false,
    host_whitelist: false,
    host_blacklist: false,
    allow_trailing_dot: false,
    allow_protocol_relative_urls: false,
    disallow_auth: false
}

isURL(string, options)

host_whitelisty host_blacklistpueden ser matrices de hosts. También admiten expresiones regulares.

let options = {
    host_blacklist: ['foo.com', 'bar.com'],
}

isURL('http://foobar.com', options) // => true
isURL('http://foo.bar.com/', options) // => true
isURL('http://qux.com', options) // => true

isURL('http://bar.com/', options) // => false
isURL('http://foo.com/', options) // => false


options = {
    host_blacklist: ['bar.com', 'foo.com', /\.foo\.com$/],
}

isURL('http://foobar.com', options) // => true
isURL('http://foo.bar.com/', options) // => true
isURL('http://qux.com', options) // => true

isURL('http://bar.com/', options) // => false
isURL('http://foo.com/', options) // => false
isURL('http://images.foo.com/', options) // => false
isURL('http://cdn.foo.com/', options) // => false
isURL('http://a.b.c.foo.com/', options) // => false

1
¡Agradable! La biblioteca pequeña (menos de 40k minificados), biblioteca popular (más de 3 millones de descargas semanales en npm), le brinda mucha flexibilidad para especificar la validez de las URL para su caso de uso particular, y tiene una serie de otros validadores además de la URL. Esta es, de lejos, la mejor respuesta, en mi humilde opinión.
Javid Jamae

4

Una función que he estado usando para validar una "cadena" de URL es:

var matcher = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/;

function isUrl(string){
  return matcher.test(string);
}

Esta función devolverá un valor booleano si la cadena es una URL.

Ejemplos:

isUrl("https://google.com");     // true
isUrl("http://google.com");      // true
isUrl("http://google.de");       // true
isUrl("//google.de");            // true
isUrl("google.de");              // false
isUrl("http://google.com");      // true
isUrl("http://localhost");       // true
isUrl("https://sdfasd");         // false

4

Esto es bastante difícil de hacer con regex puro porque las URL tienen muchos 'inconvenientes'.

  1. Por ejemplo, los nombres de dominio tienen restricciones complicadas en guiones:

    a. Se permite tener muchos guiones consecutivos en el medio.

    si. pero el primer carácter y el último carácter del nombre de dominio no pueden ser un guión

    C. Los caracteres tercero y cuarto no pueden ser ambos guiones

  2. Del mismo modo, el número de puerto solo puede estar en el rango 1-65535. Esto es fácil de verificar si extrae la parte del puerto y la convierte, intpero es bastante difícil de verificar con una expresión regular.

  3. Tampoco hay una manera fácil de verificar extensiones de dominio válidas. Algunos países tienen dominios de segundo nivel (como 'co.uk'), o la extensión puede ser una palabra larga como '.international'. Y se agregan nuevos TLD regularmente. Este tipo de cosas solo se pueden verificar con una lista codificada. (ver https://en.wikipedia.org/wiki/Top-level_domain )

  4. Luego están las direcciones URL de imanes, las direcciones ftp, etc. Todas tienen requisitos diferentes.

Sin embargo, aquí hay una función que maneja casi todo excepto:

  • Caso 1. c
  • Acepta cualquier número de puerto de 1-5 dígitos
  • Acepta cualquier extensión de 2 a 13 caracteres.
  • No acepta ftp, imán, etc.

function isValidURL(input) {
    pattern = '^(https?:\\/\\/)?' + // protocol
        '((([a-zA-Z\\d]([a-zA-Z\\d-]{0,61}[a-zA-Z\\d])*\\.)+' + // sub-domain + domain name
        '[a-zA-Z]{2,13})' + // extension
        '|((\\d{1,3}\\.){3}\\d{1,3})' + // OR ip (v4) address
        '|localhost)' + // OR localhost
        '(\\:\\d{1,5})?' + // port
        '(\\/[a-zA-Z\\&\\d%_.~+-:@]*)*' + // path
        '(\\?[a-zA-Z\\&\\d%_.,~+-:@=;&]*)?' + // query string
        '(\\#[-a-zA-Z&\\d_]*)?$'; // fragment locator
    regex = new RegExp(pattern);
    return regex.test(input);
}

let tests = [];
tests.push(['', false]);
tests.push(['http://en.wikipedia.org/wiki/Procter_&_Gamble', true]);
tests.push(['https://sdfasd', false]);
tests.push(['http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707', true]);
tests.push(['https://stackoverflow.com/', true]);
tests.push(['https://w', false]);
tests.push(['aaa', false]);
tests.push(['aaaa', false]);
tests.push(['oh.my', true]);
tests.push(['dfdsfdsfdfdsfsdfs', false]);
tests.push(['google.co.uk', true]);
tests.push(['test-domain.MUSEUM', true]);
tests.push(['-hyphen-start.gov.tr', false]);
tests.push(['hyphen-end-.com', false]);
tests.push(['https://sdfasdp.international', true]);
tests.push(['https://sdfasdp.pppppppp', false]);
tests.push(['https://sdfasdp.ppppppppppppppppppp', false]);
tests.push(['https://sdfasd', false]);
tests.push(['https://sub1.1234.sub3.sub4.sub5.co.uk/?', true]);
tests.push(['http://www.google-com.123', false]);
tests.push(['http://my--testdomain.com', false]);
tests.push(['http://my2nd--testdomain.com', true]);
tests.push(['http://thingiverse.com/download:1894343', true]);
tests.push(['https://medium.com/@techytimo', true]);
tests.push(['http://localhost', true]);
tests.push(['localhost', true]);
tests.push(['localhost:8080', true]);
tests.push(['localhost:65536', true]);
tests.push(['localhost:80000', false]);
tests.push(['magnet:?xt=urn:btih:123', true]);

for (let i = 0; i < tests.length; i++) {
    console.log('Test #' + i + (isValidURL(tests[i][0]) == tests[i][1] ? ' passed' : ' failed') + ' on ["' + tests[i][0] + '", ' + tests[i][1] + ']');
}


1

Creo que usar la API de URL nativa es mejor que los patrones complejos de expresiones regulares como sugirió @pavlo. Sin embargo, tiene algunos inconvenientes que podemos solucionar con algún código adicional. Este enfoque falla para la siguiente URL válida.

//cdn.google.com/script.js

Podemos agregar el protocolo faltante de antemano para evitarlo. Tampoco detecta la siguiente URL no válida.

http://w
http://..

Entonces, ¿por qué verificar toda la URL? solo podemos verificar el dominio. Tomé prestada la expresión regular para verificar el dominio desde aquí .

function isValidUrl(string) {
    if (string && string.length > 1 && string.slice(0, 2) == '//') {
        string = 'http:' + string; //dummy protocol so that URL works
    }
    try {
        var url = new URL(string);
        return url.hostname && url.hostname.match(/^([a-z0-9])(([a-z0-9-]{1,61})?[a-z0-9]{1})?(\.[a-z0-9](([a-z0-9-]{1,61})?[a-z0-9]{1})?)?(\.[a-zA-Z]{2,4})+$/) ? true : false;
    } catch (_) {
        return false;
    }
}

El hostnameatributo es una cadena vacía para javascript:void(0), por lo que también funciona para eso, y también puede agregar un verificador de dirección IP. Me gustaría seguir con la API nativa, y espero que comience a admitir todo en un futuro próximo.


Interesante, pero aún puede necesitar trabajar en la expresión regular ya que ahora se introducen falsos negativos que new URLno tiene en las pruebas que he hecho. Esto es llamar: http://142.42.1.1 //falsey bloquear cadenas altas de Unicode.
aamarks

1

La pregunta solicita un método de validación para una URL como stackoverflow , sin el protocolo o ningún punto en el nombre de host. Por lo tanto, no se trata de validar sintaxis de URL, sino de verificar si es una URL válida, llamándola realmente.

Intenté varios métodos para saber si la url true existe y se puede llamar desde el navegador, pero no encontré ninguna forma de probar con javascript el encabezado de respuesta de la llamada:

  • agregar un elemento de anclaje está bien para activar el click()método.
  • hacer una llamada ajax a la url desafiante con 'GET'está bien, pero tiene varias limitaciones debido a las CORSpolíticas y no es el caso de usar ajax, ya que la url puede estar fuera del dominio de mi servidor.
  • El uso de la API fetch tiene una solución similar a ajax.
  • Otro problema es que tengo mi servidor bajo httpsprotocolo y produce una excepción al llamar a URL no seguras.

Entonces, la mejor solución que se me ocurre es obtener alguna herramienta para realizar CURLusando JavaScript intentando algo como curl -I <url>. Lamentablemente no encontré ninguno y aparentemente no es posible. Agradeceré cualquier comentario sobre esto.

Pero, al final, tengo un servidor ejecutándose PHPy, como uso Ajax para casi todas mis solicitudes, escribí una función en el lado del servidor para realizar la solicitud de curl allí y volver al navegador.

Con respecto a la url de una sola palabra en la pregunta 'stackoverflow', me llevará a https://daniserver.com.ar/stackoverflowdonde daniserver.com.ar es mi propio dominio.


El OP probablemente debería haber indicado más de cuál era su intención. El problema ciertamente varía según sus necesidades y si es más importante excluir falsos positivos o incluir falsos negativos. Como se plantea el problema, parece que no hay respuesta para mí. ¿Realmente puedes tomar fooy asumir que es http o https o .com o .es o cualquiera de los innumerables sufijos? ¿Sigues tirando el fregadero de la cocina hasta que te vuelves verdadero?
aamarks

1

Este parece ser uno de los problemas más difíciles en CS;)

Aquí hay otra solución incompleta que funciona lo suficientemente bien para mí y mejor que las otras que he visto aquí. Estoy usando una entrada [type = url] para esto para soportar IE11, de lo contrario sería mucho más simple usar window.URL para realizar la validación en su lugar:

const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
function isValidIpv4(ip) {
  if (!ipv4Regex.test(ip)) return false;
  return !ip.split('.').find(n => n > 255);
}

const domainRegex = /(?:[a-z0-9-]{1,63}\.){1,125}[a-z]{2,63}$/i;
function isValidDomain(domain) {
  return isValidIpv4(domain) || domainRegex.test(domain);
}

let input;
function validateUrl(url) {
  if (! /^https?:\/\//.test(url)) url = `http://${url}`; // assuming Babel is used
  // to support IE11 we'll resort to input[type=url] instead of window.URL:
  // try { return isValidDomain(new URL(url).host) && url; } catch(e) { return false; }
  if (!input) { input = document.createElement('input'); input.type = 'url'; }
  input.value = url;
  if (! input.validity.valid) return false;
  const domain = url.split(/^https?:\/\//)[1].split('/')[0].split('@').pop();
  return isValidDomain(domain) && url;
}

console.log(validateUrl('google'), // false
  validateUrl('user:pw@mydomain.com'),
  validateUrl('https://google.com'),
  validateUrl('100.100.100.100/abc'),
  validateUrl('100.100.100.256/abc')); // false

Para aceptar entradas incompletas como "www.midominio.com", también será válido suponiendo que el protocolo es "http" en esos casos y devolverá la URL válida si la dirección es válida. Devuelve falso cuando no es válido.

También admite dominios IPv4, pero no IPv6.


1

En mi caso, mi único requisito es que la entrada del usuario no se interpretará como un enlace relativo cuando se coloca en el href de una etiqueta y las respuestas aquí fueron un poco OTT para eso o URL permitidas que no cumplen mis requisitos, por lo que esto es con lo que voy:

^https?://.+$

Lo mismo podría lograrse con bastante facilidad sin expresiones regulares.


1

esta trabajando conmigo

function isURL(str) {
  var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
  var pattern = new RegExp(regex); 
return pattern.test(str);
}

1
Esta respuesta ya fue dada anteriormente hace 4 años por kavitha Reddy.
aamarks 01 de

Lo hice más simple y abstracto
HeshamSalama

1

Si puede cambiar el tipo de entrada, creo que esta solución sería mucho más fácil:

Puede usarlo simplemente type="url"en su entrada y verificarlo checkValidity()en js

P.ej:

your.html

<input id="foo" type="url">

your.js

// The selector is JQuery, but the function is plain JS
$("#foo").on("keyup", function() {
    if (this.checkValidity()) {
        // The url is valid
    } else {
        // The url is invalid
    }
});

1

Este definitivamente no es el enfoque más efectivo, pero es legible y fácil de adaptar a lo que necesite. Y es más fácil agregar expresiones regulares / complejidad desde aquí. Así que aquí hay un enfoque muy pragmático

const validFirstBits = ["ftp://", "http://", "https://", "www."];
const invalidPatterns = [" ", "//.", ".."];

export function isUrl(word) {
// less than www.1.dk
if (!word || word.length < 8) return false;

// Let's check and see, if our candidate starts with some of our valid first bits
const firstBitIsValid = validFirstBits.some(bit => word.indexOf(bit) === 0);
if (!firstBitIsValid) return false;

const hasInvalidPatterns = invalidPatterns.some(
    pattern => word.indexOf(pattern) !== -1,
);

if (hasInvalidPatterns) return false;

const dotSplit = word.split(".");
if (dotSplit.length > 1) {
    const lastBit = dotSplit.pop(); // string or undefined
    if (!lastBit) return false;
    const length = lastBit.length;
    const lastBitIsValid =
        length > 1 || (length === 1 && !isNaN(parseInt(lastBit)));
    return !!lastBitIsValid;
}

    return false;
}

PRUEBA:

import { isUrl } from "./foo";

describe("Foo", () => {
    test("should validate correct urls correctly", function() {
        const validUrls = [
            "http://example.com",
            "http://example.com/blah",
            "http://127.0.0.1",
            "http://127.0.0.1/wow",
            "https://example.com",
            "https://example.com/blah",
            "https://127.0.0.1:1234",
            "ftp://example.com",
            "ftp://example.com/blah",
            "ftp://127.0.0.1",
            "www.example.com",
            "www.example.com/blah",
        ];

        validUrls.forEach(url => {
            expect(isUrl(url) && url).toEqual(url);
        });
    });

    test("should validate invalid urls correctly", function() {
        const inValidUrls = [
            "http:// foo.com",
            "http:/foo.com",
            "http://.foo.com",
            "http://foo..com",
            "http://.com",
            "http://foo",
            "http://foo.c",
        ];

        inValidUrls.forEach(url => {
            expect(!isUrl(url) && url).toEqual(url);
        });
    });
});

1

Mathias Bynens ha compilado una lista de expresiones regulares de URL conocidas con URL de prueba. Hay pocas razones para escribir una nueva expresión regular; simplemente elija uno existente que más le convenga.

Pero la tabla de comparación para esas expresiones regulares también muestra que es casi imposible hacer la validación de URL con una sola expresión regular. Todas las expresiones regulares en la lista de Bynens producen falsos positivos y falsos negativos.

Le sugiero que use un analizador de URL existente (por ejemplo new URL('http://www.example.com/')en JavaScript) y luego aplique las comprobaciones que desea realizar en la forma analizada y normalizada de la URL resp. sus componentes El uso de la URLinterfaz de JavaScript tiene el beneficio adicional de que solo aceptará las URL que el navegador realmente acepte.

También debe tener en cuenta que las URL técnicamente incorrectas aún pueden funcionar. Por ejemplo http://w_w_w.example.com/, http://www..example.com/, http://123.example.com/todos tienen una parte de host no válido, pero todos los navegadores sé que van a tratar de abrirlos sin quejas, y cuando se especifique las direcciones IP de esos nombres no válidos en/etc/hosts/ tales direcciones URL incluso trabajar, pero sólo en su ordenador.

Por lo tanto, la pregunta no es tanto si una URL es válida, sino qué URL funcionan y deberían permitirse en un contexto particular.

Si desea realizar la validación de URL, hay muchos detalles y casos extremos que son fáciles de pasar por alto:

  • Las URL pueden contener credenciales como en http://user:password@www.example.com/ .
  • Los números de puerto deben estar en el rango de 0-65535, pero es posible que desee excluir el puerto comodín 0.
  • Los números de puerto pueden tener ceros a la izquierda como en http://www.example.com:000080/ .
  • Las direcciones IPv4 de ninguna manera están restringidas a 4 enteros decimales en el rango de 0-255. Puede usar de uno a cuatro enteros, y pueden ser decimales, octales o hexadecimales. Las URL https: //010.010.000010.010/ , https: //0x8.0x8.0x0008.0x8/ , https: //8.8.2056/ , https: //8.526344/ , https: // 134744072 / son todas válidas y solo formas creativas de escribir https://8.8.8.8/ .
  • Permitir direcciones de bucle invertido ( http://127.0.0.1/ ), direcciones IP privadas ( http://192.168.1.1 ), direcciones locales de enlace ( http://169.254.100.200 ), etc., puede tener un impacto en la seguridad o intimidad. Si, por ejemplo, los permite como la dirección de los avatares de los usuarios en un foro, hace que los navegadores de los usuarios envíen solicitudes de red no solicitadas en su red local y en Internet de cosas que tales solicitudes pueden causar cosas divertidas y no tan divertidas pasar en tu casa.
  • Por las mismas razones, es posible que desee descartar enlaces a nombres de host no totalmente calificados, en otras palabras, nombres de host sin punto.
  • Pero los nombres de host siempre pueden tener un punto final (como en http://www.stackoverflow.com.).
  • La parte del nombre de host de un enlace puede contener corchetes angulares para direcciones IPv6 como en http: // [:: 1] .
  • Las direcciones IPv6 también tienen rangos para redes privadas o direcciones locales de enlace, etc.
  • Si bloquea ciertas direcciones IPv4, tenga en cuenta que, por ejemplo, https://127.0.0.1 y https: // [:: ffff: 127.0.0.1] apuntan al mismo recurso (si el dispositivo de bucle invertido de su máquina está preparado para IPv6) )
  • La parte del nombre de host de las URL ahora puede contener Unicode, por lo que el rango de caracteres [-0-9a-zA-z]definitivamente ya no es suficiente.
  • Muchos registros para dominios de nivel superior definen restricciones específicas, por ejemplo, en el conjunto permitido de caracteres Unicode. O subdividen su espacio de nombres (como co.uky muchos otros).
  • Los dominios de nivel superior no deben contener dígitos decimales, y el guión no está permitido a menos que el prefijo de etiqueta A de IDN "xn--".
  • Los dominios de nivel superior Unicode (y su codificación punycode con "xn--") todavía deben contener solo letras, pero ¿quién quiere verificar eso en una expresión regular?

Cuál de estas limitaciones y reglas se aplica es una cuestión de requisitos y gustos del proyecto.

Recientemente escribí un validador de URL para una aplicación web que es adecuada para URL proporcionadas por el usuario en foros, redes sociales o similares. Siéntase libre de usarlo como base para su propio:

También he escrito una publicación de blog The Gory Details of URL Validation con información más detallada.


1

Cambio la función a Match + y hago un cambio aquí con las barras y su trabajo: (http: // y https) ambos

function isValidUrl(userInput) {
    var res = userInput.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
    if(res == null)
       return false;
    else
       return true;
}

0

Aquí hay una comprobación muy simple para asegurarse de que haya un protocolo válido y que la extensión del dominio debe tener dos o más caracteres.

is_valid_url = ( $url ) => {

    let $url_object = null;

    try {
        $url_object = new URL( $url );
    } catch ( $error ) {
        return false;
    }

    const $protocol = $url_object.protocol;
    const $protocol_position = $url.lastIndexOf( $protocol );
    const $domain_extension_position = $url.lastIndexOf( '.' );

    return (
        $protocol_position === 0 &&
        [ 'http:', 'https:' ].indexOf( $protocol ) !== - 1 &&
        $domain_extension_position > 2 && $url.length - $domain_extension_position > 2
    );

};

0

Si necesita soporte también https://localhost:3000, utilice esta versión modificada de la expresión regular de [Devshed].

    function isURL(url) {
        if(!url) return false;
        var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
            '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
            '((\\d{1,3}\\.){3}\\d{1,3}))|' + // OR ip (v4) address
            'localhost' + // OR localhost
            '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
            '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
            '(\\#[-a-z\\d_]*)?$', 'i'); // fragment locator
        return pattern.test(url);
    }

0

Hay un par de pruebas que usan el constructor de URL que no delinean si la entrada es una cadena o un objeto de URL.

// Testing whether something is a URL
function isURL(url) {
    return toString.call(url) === "[object URL]";
}

// Testing whether the input is both a string and valid url:
function isUrl(url) {
    try {
        return toString.call(url) === "[object String]" && !!(new URL(url));
    } catch (_) {
        return false;  
    }
}

0

Actualización 2020. Para ampliar las excelentes respuestas de @iamnewton y @Fernando Chavez Herrera, he comenzado a ver que @se utilizan en la ruta de las URL.

Entonces la expresión regular actualizada es:

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');

Si desea permitirlo en la cadena de consulta y el hash, use:

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');

Dicho esto, no estoy seguro de si hay una regla de documento técnico que no se permita @en la cadena de consulta o hash.


0

Ya hay muchas respuestas, pero aquí hay otra contribución: tomada directamente de la URLverificación de validez de polyfill, use un inputelemento con type="url"para aprovechar la verificación de validez incorporada en el navegador:

var inputElement = doc.createElement('input');
inputElement.type = 'url';
inputElement.value = url;

if (!inputElement.checkValidity()) {
    throw new TypeError('Invalid URL');
}

Fuente

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.