1

Estoy tratando de conseguir el src de una imagen usando Expresiones Regulares.
Sin embargo parece estar ignorando el primer (.jpg") que es la condición especificada para terminar.

Prueba Pagina: http://www.regexr.com

Expresion:

(<div id="imgTagWrapperId")[\s\S+]+(src)[\s\S+]+(.jpg")

String HTML:

    <title>Redmi 7 3GB RAM 32GB ROM Versión Global Dual SIM Snapdragon 632 Octa Core 4000mAh Redmi Seven Smartphone (Black): Amazon.es: Electrónica</title> dddddwewdff


<div id="imgTagWrapperId" class="imgTagWrapper" style="height: 668px;">
    <img alt="Xiaomi Redmi Note 7 128GB + 4GB RAM 6.3&amp;quot; FHD+ LTE Factory Unlocked 48MP GSM Smartphone (Global Version) (Neptune Blue)" src="https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX679_.jpg" data-old-hires="https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SL1000_.jpg" class="a-dynamic-image  a-stretch-horizontal" id="landingImage" data-a-dynamic-image="{&quot;https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX522_.jpg&quot;:[522,522],&quot;https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX569_.jpg&quot;:[569,569],&quot;https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX385_.jpg&quot;:[385,385],&quot;https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX342_.jpg&quot;:[342,342],&quot;https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX679_.jpg&quot;:[679,679],&quot;https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX466_.jpg&quot;:[466,466],&quot;https://images-na.ssl-images-amazon.com/images/I/61eNdh8EmAL._SX425_.jpg&quot;:[425,425]}" style="max-width: 514px; max-height: 514px;">
        <div id="magnifierLens" style="position: absolute; background-image: url(&quot;https://images-na.ssl-images-amazon.com/images/G/01/apparel/rcxgs/tile._CB483369105_.gif&quot;); cursor: pointer; width: 342px; height: 106px; left: 172px; top: 77px;"/>
    </div>
rencinas
  • 1,267
  • 11
  • 29
Yonkykong
  • 31
  • 3

3 Answers3

1

El problema que estabas teniendo es que tu regex era "greddy" o "non-lazy" por tanto no se detenía en la primera ocurrencia sino que buscaba hasta el final del documento.

La solución como tal es bastante sencilla pero me ha costado encontrarla:

(<div id="imgTagWrapperId")[\s\S+]+(src)[\s\S+]+(.jpg")  //Busca hasta el último .jpg"

(<div id="imgTagWrapperId")[\s\S+]+(src)[\s\S+]+?(.jpg") // Busca hasta que encuentra .jpg"

Lo que estamos haciendo es lo siguiente con "?" (Hacer que el regex sea "vago" e intente buscar las menores coincidencias posibles)
Le indicamos que la siguiente búsqueda la realice solo una vez, de esta manera no te incluye cualquier carácter [\s\S] entre el inicio y tu final (.jpg"). Solamente la primera vez que lo encuentre

Este artículo explica mucho mejor lo que he expuesto: https://www.regular-expressions.info

rencinas
  • 1,267
  • 11
  • 29
1

Las expresiones regulares son por defecto "voraces" (greedy), es decir, que se extienden lo máximo posible. Esta parte de tu expresión:

[\s\S+]+(.jpg")

significa "cualquier carácter no blanco hasta que aparezca jpg" (el punto delante de jpg por cierto, debiste haberlo escapado, pues si no encajará con cualquier carácter). Naturalmente, si en la cadena aparece varias veces la subcadena "jpg" sin espacios entre ambas, el primer "jpg" encajará con la parte "cualquier caracter no blanco", por lo que seguirá "consumiendo" texto hasta encontrarse con el siguiente "jpg".

Lo que tú querías era "cualquier carácter no blanco hasta que aparezca el primer jpg". Esto es lo que se llama la variante lazy (non-greedy) que se logra poniendo un interrogante tras la parte que podría encajar muchos caracteres, lo que hará entonces que encaje el mínimo posible. En tu caso:

[\s\S+]+?(.jpg")

Al margen de esto, usas expresiones entre paréntesis, las cuales sirven para crear "grupos de captura". Pero lo que estás capturando en ellas en realidad no te interesa, ya que lo que realmente te interesa es la parte que está dentro del src. Por otro lado tampoco veo por qué te limitas a rutas que terminen en jpg ¿y si la ruta es un png?

Creo que una expresión regular mejor sería:

<div id="imgTagWrapperId"[\s\S+]+src="([\s\S+]+?jpg)"

Esta expresión básicamente es igual a la tuya, pero tiene un solo grupo de captura (una sola expresión entre paréntesis) y esa capturará justamente la URL buscada. Si la imagen puede tener otros formatos distintos de jpg, puedes usar:

<div id="imgTagWrapperId"[\s\S+]+src="([\s\S+]+?)"

Demo de funcionamiento: en regex101. en regexr.com (esta última no muestra el grupo de captura, sólo el match general)

abulafia
  • 53,696
  • 3
  • 45
  • 80
0

Si bien las otras respuestas explican el porqué del problema (uso de cuantificadores greedy), creo que simplemente pasar a cuantificadores lazy no es la solución correcta ya que puede dar lugar a problemas.

Ejemplo de problema simplemente cambiando a cuantificador lazy:

<div id="imgTagWrapperId" src="hola.png"><div id="imgTagWrapperId" src="hola.jpg">

Si en el caso de arriba buscamos jpg, la expresión regular empezaría desde el primer src y como no encuentra jpg (hay un png) avanzaría hasta el segundo div, como se puede ver aquí.

La solución sería buscar [^"] dentro de src. Esto significa "cualquier caracter que no sea comillas" ya que no puede existir dentro de src="". De esta manera cuando empecemos a mirar el primer src, si no encuentra jpg no saltará hasta el segundo ya que cuando encuentre el fin de comillas, no podrá seguir consumiendo caracteres.

Así pues, la expresión regular podría ser la siguiente:

<div id="imgTagWrapperId"\s+src="([^"]+jpg)"

Tienes una demo aquí.

En esta última ya no es necesario el uso del cuantificador lazy (aunque no afectaría tenerlo puesto tampoco)

Julio
  • 3,173
  • 1
  • 7
  • 23