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

Langage Java Discussion :

[Regexp] StringIndexOutOfBoundsException dans String.replaceAll()


Sujet :

Langage Java

  1. #1
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut [Regexp] StringIndexOutOfBoundsException dans String.replaceAll()
    Bonjour à tous,

    Je viens de passer de longues minutes à m'arracher les quelques cheveux qu'il me restaient à cause d'un contenu de chaine de remplacement ...

    Voici le cas "critique" qui peut faire que vos collègues fassent appel aux gentils messieurs en blouses blanches.

    Le but : remplacer toutes les occurences de "{modele}" par une chaine saisie par l'utilisateur.

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public String test(String valeur) {
        String source = "Voici un texte avec {modele} à l'intérieur...";
        String resultat = source.replaceAll("\\{modele\\}", valeur);
        return resultat;
    }

    Dans presque tous les cas de contenu de "valeur" tout se passe bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    test("azerty") -> "Voici un texte avec azerty à l'intérieur..."
    test("a.z?e!r^t[y") -> "Voici un texte avec a.z?e!r^t[y à l'intérieur..."
    Il y a par contre au moins 2 cas qui posent problème en provoquant une StringIndexOutOfBoundsException.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    test("$") -> An exception occurred: java.lang.StringIndexOutOfBoundsException
    test("\\") -> An exception occurred: java.lang.StringIndexOutOfBoundsException
    par contre

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    test("$".replaceAll("\\$","\\\\\\$") -> "Voici un texte avec $ à l'intérieur..."
    test("\\".replaceAll("\\\\","\\\\\\\\") -> "Voici un texte avec \ à l'intérieur..."
    Notez bien que dans le cas du $ il y a 6 \.

    Donc si je place cet encodage dans ma fonction on obtient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public String test(String valeur) {
        String source = "Voici un texte avec {modele} à l'intérieur...";
        String valeur_encodee = valeur.replaceAll("\\\\","\\\\\\\\").replaceAll("\\$","\\\\\\$");
        String resultat = source.replaceAll("\\{modele\\}", valeur_encodee);
        return resultat;
    }


    Suite à la réponse #5 de Arcadia, voici le code équivalent avec "java.util.Matcher.quoteReplacement()" :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public String test(String valeur) {
        String source = "Voici un texte avec {modele} à l'intérieur...";
        String valeur_encodee = Matcher.quoteReplacement(valeur);
        String resultat = source.replaceAll("\\{modele\\}", valeur_encodee);
        return resultat;
    }
    devyan.

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2008
    Messages
    1 190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 1 190
    Par défaut
    Il y aurait bien d'autre cas ou ton truc ne marcherait pas, tout simplement parce que certain caractère tel le '\' ont un sens spécial.
    Il faut donc les "echapper", une recherche google te donnera surement du code tout pret pour faire cela correctement.

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut
    Citation Envoyé par deathness Voir le message
    Il y aurait bien d'autre cas ou ton truc ne marcherait pas, tout simplement parce que certain caractère tel le '\' ont un sens spécial.
    Il faut donc les "echapper", une recherche google te donnera surement du code tout pret pour faire cela correctement.
    J'ai géré le cas '\'.
    J'ai testé les principaux caractères de masques RegExp (.*^{[]}?!) mais seuls ces 2 cas semblent poser problème.

    J'ai pensé à et ai fait quelques recherches sans grand succès (ce qui me rassurerait plutôt) mais si tu as des exemples concrets qui plantent également n'hésite pas à me les signaler

  4. #4
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2008
    Messages
    1 190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 1 190
    Par défaut
    Et bien comme ça tu pourrais essayer des %d.
    Enfin ça dépend de comment tu affiches derrière aussi (http://docs.oracle.com/javase/tutori...berformat.html).

  5. #5
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 10
    Par défaut
    Regardes du cote des classes Pattern et Matcher.
    Perso, j'utilise ce code pour gerer tous les caracteres de maniere litteral sur un CharBuffer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Pattern pat = Pattern.compile(toRemove, Pattern.LITERAL);
    Matcher mat = pat.matcher(cbuf);
    String s = mat.replaceAll(Matcher.quoteReplacement(toAdd));

  6. #6
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut
    Citation Envoyé par Arcadia Voir le message
    Regardes du cote des classes Pattern et Matcher.
    Perso, j'utilise ce code pour gerer tous les caracteres de maniere litteral sur un CharBuffer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Pattern pat = Pattern.compile(toRemove, Pattern.LITERAL);
    Matcher mat = pat.matcher(cbuf);
    String s = mat.replaceAll(Matcher.quoteReplacement(toAdd));
    Super, merci beaucoup.

    Matcher.quoteReplacement() fait exactement ce qu'il faut.
    D'ailleurs, il ne fait que le remplacement de \ et $

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public static String quoteReplacement(String paramString)
    {
    	if ((paramString.indexOf(92) == -1) && (paramString.indexOf(36) == -1))
    		return paramString;
     
    	StringBuffer localStringBuffer = new StringBuffer();
     
    	for (int i = 0; i < paramString.length(); ++i) {
    		char c = paramString.charAt(i);
    		if (c == '\\') {
    			localStringBuffer.append('\\');
    			localStringBuffer.append('\\');
    		} else if (c == '$') {
    			localStringBuffer.append('\\');
    			localStringBuffer.append('$');
    		} else {
    			localStringBuffer.append(c);
    		}
    	}
    	return localStringBuffer.toString();
    }

    Edit : on se demande d'ailleurs pourquoi ils n'ont pas protégé la String.replaceAll() avec Matcher.quoteReplacement() alors que String.replace() l'a été ...


    devyan

  7. #7
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par devyan Voir le message
    Edit : on se demande d'ailleurs pourquoi ils n'ont pas protégé la String.replaceAll() avec Matcher.quoteReplacement() alors que String.replace() l'a été ...
    Euh, non, la plupart des gens comprennent pourquoi :

    Vois-tu, ça ne sert pas à grand-chose d'avoir un langage d'expressions de remplacements, si rien au monde ne s'en sert.
    replace() n'a pas de raison de s'en servir, puisqu'il ne reconnaît pas d'expression régulière, et donc que le remplacement est forcément constant, donc pas besoin de langage.
    Mais replaceAll() peut parfaitement identifier des groupes avec son expression régulière, qu'il peut être intéressant de reprendre dans le remplacement.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut
    Citation Envoyé par deathness Voir le message
    Et bien comme ça tu pourrais essayer des %d.
    Enfin ça dépend de comment tu affiches derrière aussi (http://docs.oracle.com/javase/tutori...berformat.html).
    J'ai fait le test avec % et ce n'est pas un cas qui plante la "String.replaceAll()".

    En aucun cas la méthode d'affichage ne doit entrer en jeu, il s'agit à ce niveau là d'un assemblage de données permettant de créer une chaîne dans la langue de l'utilisateur.

    devyan

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

Discussions similaires

  1. Regexp : Trouver ? dans un String
    Par rXpCH dans le forum Collection et Stream
    Réponses: 5
    Dernier message: 07/06/2011, 09h06
  2. Valeur hexadecimale dans String -> Long
    Par Stol dans le forum Langage
    Réponses: 2
    Dernier message: 25/03/2005, 16h31
  3. Problème de copie de string dans string
    Par kazarn dans le forum SL & STL
    Réponses: 17
    Dernier message: 15/03/2005, 18h35
  4. [String][replaceAll][Expression régulière]Remplacement multi
    Par cpr0 dans le forum Collection et Stream
    Réponses: 9
    Dernier message: 09/04/2004, 16h40
  5. [regex][string] replaceAll bogué ?
    Par 7eme dans le forum Collection et Stream
    Réponses: 4
    Dernier message: 13/11/2003, 16h36

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