IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Collection et Stream Java Discussion :

[REGEX] StackOverflowError sur fonction find


Sujet :

Collection et Stream Java

  1. #1
    Membre du Club
    Inscrit en
    Avril 2004
    Messages
    101
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 101
    Points : 58
    Points
    58
    Par défaut [REGEX] StackOverflowError sur fonction find
    Bonjour,

    j'ai une expression régulière qui lève une exception lorsque le texte source dépasse un certain nombre de caractère.
    Il s'agit d'une StackOverflowError, sans numéro de ligne et sans explication claire.
    Je ne comprend pas pourquoi cette erreur apparaît, peut-être avez vous une idée...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    		Pattern pattern = Pattern.compile("<BLOC>(\\s|.)*</BLOC>");
     
    		StringBuffer txt = new StringBuffer();
    		txt.append("<BLOC>");
    		// exception avec i > 800
    		for (int i=0; i<801; i++)
    			txt.append("a");
    		txt.append("</BLOC>");
     
    		Matcher m = pattern.matcher(txt);
    		if (m.find(0)) { // Exception in thread "main" java.lang.StackOverflowError
    			System.out.println("find");
    		}
    pour l'exemple je remplis txt avec
    <BLOC>aaaaaaaa...</BLOC>
    L'exception est la suivante :
    Exception in thread "main" java.lang.StackOverflowError
    at java.util.regex.Pattern$Loop.match(Unknown Source)
    at java.util.regex.Pattern$GroupTail.match(Unknown Source)
    at java.util.regex.Pattern$Dot.match(Unknown Source)
    at java.util.regex.Pattern$Branch.match(Unknown Source)
    at java.util.regex.Pattern$GroupHead.match(Unknown Source)
    at java.util.regex.Pattern$Loop.match(Unknown Source)
    ...ça recommence sur plusieurs dizaines de lignes
    ça fonctionne avec 800 caratères mais pas plus.

    Au passage cette expression n'est pas de moi et je connais pas la raison du (\\s|.)* dans le pattern plutôt que .*
    Avec .* ça fonctionne sans problème, mais je voudrais tout de même bien comprendre cette l'origine de cette exception.

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par _Eric_ Voir le message
    Au passage cette expression n'est pas de moi et je connais pas la raison du (\\s|.)* dans le pattern plutôt que .*
    J'allais justement te demander la même chose

    Citation Envoyé par _Eric_ Voir le message
    Avec .* ça fonctionne sans problème, mais je voudrais tout de même bien comprendre cette l'origine de cette exception.
    Moi aussi. Ou plutôt .*? qui permet de prendre la plus petite chaine correspondante (au lieu de la plus grande).

    Par exemple avec la chaine d'entrée : "<BLOC>a</BLOC><BLOC>b</BLOC>" :
    • <BLOC>.*</BLOC> te trouvera un résultat : "<BLOC>a</BLOC><BLOC>b</BLOC>"
    • <BLOC>.*?</BLOC> te trouvera deux résultats : "<BLOC>a</BLOC>" et "<BLOC>b</BLOC>"


    Au passage pour de simple caractère plutôt que le (a|b) j'utiliserais [ab].



    Pour en revenir à ton erreur, il s'agit d'un problème de récursion infini (ou trop important en tout cas).
    Si mes souvenirs sont bon il existe des regexps "foireuses" qui fonctionnent très bien avec de petites valeurs mais dont le coût est exponentielle, et qui peuvent rapidement consommer un max de ressource voir carrément exploser.

    Il semblerait que ce soit le cas ici...



    a++

  3. #3
    Membre du Club
    Inscrit en
    Avril 2004
    Messages
    101
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 101
    Points : 58
    Points
    58
    Par défaut
    Merci pour la précision
    .*?
    J'ai corrigé l'expression avec .* au lieu de (\\s|.)* (dans notre cas il n'y a qu'un seul groupe de balise possible) donc ça fonctionne pour mon appli, par contre c'est un peu frustrant de savoir que ça peux réapparaitre sans prévenir.
    D'autant plus qu'on ne peut pas catcher l'erreur apparemment.

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par _Eric_ Voir le message
    J'ai corrigé l'expression avec .* au lieu de (\\s|.)* (dans notre cas il n'y a qu'un seul groupe de balise possible) donc ça fonctionne pour mon appli,
    Je te conseillerais quand même d'utiliser .*?, car elle s'arrêtera au premier </bloc> trouvé. Sinon la regexp analysera toutes la chaine jusqu'à la fin pour voir s'il n'y a pas un autre </bloc>...




    Citation Envoyé par _Eric_ Voir le message
    par contre c'est un peu frustrant de savoir que ça peux réapparaitre sans prévenir.
    D'autant plus qu'on ne peut pas catcher l'erreur apparemment.
    On peut très bien catcher l'erreur... mais ce n'est pas très propre de faire cela

    Pour moi c'est une erreur de développement : la regexp ne supporte pas de données "trop" importante.


    a++

  5. #5
    Membre du Club
    Inscrit en
    Avril 2004
    Messages
    101
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 101
    Points : 58
    Points
    58
    Par défaut
    Effectivement ce doit être plus performant avec le "?"
    Et en effet la catch fonctionne également, ne voyant pas ma classe dans la StackTrace j'ai cru que l'erreur passait outre.

    Merci pour ces infos.

  6. #6
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par _Eric_ Voir le message
    Et en effet la catch fonctionne également, ne voyant pas ma classe dans la StackTrace j'ai cru que l'erreur passait outre.
    C'est juste qu'il doit y avoir plus de 10000 appels de méthodes donc le stacktrace est tronqué

    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [VI-2003] Fonction FIND sur Visio
    Par capounet dans le forum Visio
    Réponses: 0
    Dernier message: 22/12/2010, 14h17
  2. [E-03] Aide sur la Fonction .Find dans VBA
    Par Gunsx dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 29/01/2009, 22h36
  3. encore un problème, cette fois sur la fonction Find
    Par NulenVBA dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 16/12/2008, 19h37
  4. [RegEx] Regex sur fonction STRPOS() ?
    Par fakir22 dans le forum Langage
    Réponses: 3
    Dernier message: 06/05/2008, 15h58
  5. Aide sur la fonction Find
    Par Toad08 dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 28/03/2008, 00h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo