2010-04-04 5 views
0

Comment puis-je correspondre à une chaîne d'URL comme ceci:Java Regex Matcher Question

img src = "https://stackoverflow.com/a/b/c/d/someimage.jpg"

où seul le nom de domaine et l'extension de fichier (jpg) est fixe tandis que d'autres sont des variables?

Le code suivant ne semble pas travailler:

Pattern p = Pattern.compile("<img src=\"http://stachoverflow.com/.*jpg"); 
    // Create a matcher with an input string 
    Matcher m = p.matcher(url); 
    while (m.find()) { 
    String s = m.toString(); 
    } 
+1

Peut-être parce qu'il est en fait Stackoverflow avec un '' K' au lieu de h'? ;) En outre, la bonne approche serait d'utiliser un analyseur HTML: http://stackoverflow.com/search?q=parse+html+with+regex – BalusC

+0

Ceci est un problème qui est bien dans les limites de regex, beaucoup de L'analyse HTML n'est pas adaptée à la regex, mais je ne vois pas de problème à extraire un chemin d'image de cette manière. – Michael

+2

@Michael: '' pourrait devenir un problème, en fonction de ce que l'expression rationnelle est utilisée pour ... –

Répondre

1

D'abord, je voudrais utiliser la méthode group() pour récupérer le texte correspondant, non toString(). Mais c'est probablement juste la partie URL que vous voulez, donc j'utiliserais des parenthèses pour capturer cette partie et appeler group(1) pour le récupérer. Deuxièmement, je ne supposerais pas src était le premier attribut de la balise <img>. Sur SO, par exemple, il est généralement précédé d'un attribut class. Vous voulez ajouter quelque chose pour correspondre aux attributs intermédiaires, mais assurez-vous qu'il ne peut pas correspondre au-delà de la fin de la balise. [^<>]+ suffira probablement. Troisièmement, j'utiliserais quelque chose de plus restrictif que .* pour faire correspondre la partie inconnue avec le chemin. Il y a toujours une chance que vous trouverez deux URL sur une ligne, comme ceci:

<img src="http://so.com/foo.jpg"> blah <img src="http://so.com/bar.jpg"> 

Dans ce cas, le .* dans votre regex combler l'écart, vous donnant un match où vous vouliez deux. Encore une fois, [^<>]* sera probablement assez restrictif.

Il existe également plusieurs autres problèmes potentiels. Les valeurs d'attribut sont-elles toujours entourées de guillemets, ou pourraient-elles être à guillemets simples ou ne pas être du tout citées? Y aura-t-il des espaces autour du =? Les noms d'éléments et d'attributs sont-ils toujours en minuscules?

... et je pourrais continuer. Comme cela a été souligné à plusieurs reprises ici sur SO, les expressions régulières ne sont pas vraiment le bon outil pour travailler avec HTML. Ils peuvent généralement gérer des tâches simples comme celle-ci, mais il est essentiel que vous compreniez leurs limites.

Voici ma version révisée de votre regex (comme chaîne littérale Java):

"(?i)<img[^<>]+src\\s*=\\s*[\"']?(http://stackoverflow\\.com/[^<>]+\\.jpg)" 
+0

@Alan: '' serait toujours reconnu en utilisant '[^ <>]'.C'est juste un autre exemple, pourquoi c'est si dangereux ... –

+1

@chris: Oui, je couvrais juste quelques-uns des problèmes les plus communs trouvés dans le HTML valide et bien intentionné. Une liste complète de getchas potentiels remplirait un livre épais. –

2

Il y avait quelques problèmes avec la regex correspondant à la chaîne d'exemple que vous avez donné. Vous étiez proche, cependant. Voici votre code fixe pour le faire fonctionner:

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class TCPChat { 

    static public void main(String[] args) { 
    String url = "<img src=\"http://stackoverflow.com/a/b/c/d/someimage.jpg\">"; 
    Pattern p = Pattern.compile("<img src=\"http://stackoverflow.com/.*jpg\">"); 
    // Create a matcher with an input string 
    Matcher m = p.matcher(url); 
    while (m.find()) { 
     String s = m.toString(); 
     System.out.println(s); 
    } 
    } 
} 
+0

Je terminerais la regex avec '. * \. Jpg'. C'est une petite chose, mais cela empêche de faire correspondre des choses comme "myimage.notreallyajpg" – mpen

+0

Vous devez double-échapper le backslash. Votre exemple n'aurait pas été compilé (si c'était le problème ** réel **, vous auriez dû dire qu'au lieu de simplement "ça ne marche pas"). – BalusC