108 votes

Java Remplacer plusieurs sous-chaînes différentes dans une chaîne en une seule fois (ou de la manière la plus efficace)

J'ai besoin de remplacer plusieurs sous-chaînes différentes dans une chaîne de la manière la plus efficace possible. Est-ce qu'il y a un autre moyen que la force brute de remplacer chaque champ en utilisant string.replace ?

109voto

Todd Owen Points 4477

Si la chaîne sur laquelle vous travaillez est très longue, ou si vous travaillez sur de nombreuses chaînes, il peut être intéressant d'utiliser un java.util.regex.Matcher (cela demande du temps pour la compilation, et ne sera donc pas efficace si votre entrée est très petite ou si votre motif de recherche change fréquemment).

Voici un exemple complet, basé sur une liste de jetons tirés d'une carte. (Utilise StringUtils de Apache Commons Lang).

Map<String,String> tokens = new HashMap<String,String>();
tokens.put("cat", "Garfield");
tokens.put("beverage", "coffee");

String template = "%cat% really needs some %beverage%.";

// Create pattern of the format "%(cat|beverage)%"
String patternString = "%(" + StringUtils.join(tokens.keySet(), "|") + ")%";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(template);

StringBuffer sb = new StringBuffer();
while(matcher.find()) {
    matcher.appendReplacement(sb, tokens.get(matcher.group(1)));
}
matcher.appendTail(sb);

System.out.println(sb.toString());

Une fois l'expression régulière compilée, l'analyse de la chaîne d'entrée est généralement très rapide (bien que si votre expression régulière est complexe ou implique un retour en arrière, vous devrez toujours procéder à une analyse comparative pour le confirmer).

1 votes

Oui, mais le nombre d'itérations doit être évalué.

6 votes

Je pense que vous devriez échapper les caractères spéciaux dans chaque jeton avant de faire "%(" + StringUtils.join(tokens.keySet(), "|") + ")%";

0 votes

Notez qu'il est possible d'utiliser StringBuilder pour plus de rapidité. StringBuilder n'est pas synchronisé. éditer whoops ne fonctionne qu'avec java 9

7voto

Steve McLeod Points 19016

Si vous devez modifier une chaîne de caractères plusieurs fois, il est généralement plus efficace d'utiliser un StringBuilder. (mais mesurez vos performances pour le savoir) :

String str = "The rain in Spain falls mainly on the plain";
StringBuilder sb = new StringBuilder(str);
// do your replacing in sb - although you'll find this trickier than simply using String
String newStr = sb.toString();

Chaque fois que vous effectuez un remplacement sur une chaîne, un nouvel objet chaîne est créé, car les chaînes sont immuables. StringBuilder est mutable, c'est-à-dire qu'il peut être modifié autant que vous le souhaitez.

1 votes

Je crains que cela ne serve à rien. Lorsque la longueur de la corde de remplacement diffère de celle de la corde d'origine, il faut procéder à un décalage, ce qui peut s'avérer plus coûteux que de reconstruire la corde à l'identique. Ou ai-je oublié quelque chose ?

4voto

Brian Agnew Points 143181

StringBuilder remplacera plus efficacement, puisque son tableau de caractères peut être spécifié à la longueur voulue. StringBuilder est conçu pour plus que l'apposition !

Bien sûr, la vraie question est de savoir s'il s'agit d'une optimisation trop poussée ? La JVM gère très bien la création d'objets multiples et le ramassage des ordures qui s'ensuit, et comme pour toutes les questions d'optimisation, ma première question est de savoir si vous avez mesuré ce phénomène et déterminé qu'il s'agit d'un problème.

2voto

green Points 5032

Rythm, un moteur de template Java, est désormais disponible avec une nouvelle fonctionnalité appelée Mode d'interpolation des chaînes de caractères qui vous permet de faire quelque chose comme :

String result = Rythm.render("@name is inviting you", "Diana");

Le cas ci-dessus montre que vous pouvez passer un argument au modèle par position. Rythm vous permet également de passer des arguments par nom :

Map<String, Object> args = new HashMap<String, Object>();
args.put("title", "Mr.");
args.put("name", "John");
String result = Rythm.render("Hello @title @name", args);

Note Rythm est TRÈS RAPIDE, environ 2 à 3 fois plus rapide que String.format et velocity, parce qu'il compile le modèle en byte code java, la performance d'exécution est très proche de la concaténation avec StringBuilder.

Liens :

0 votes

Il s'agit d'une capacité très ancienne disponible dans de nombreux langages de modélisation tels que velocity, JSP, etc. De plus, cela ne répond pas à la question qui n'exige pas que les chaînes de recherche soient dans un format prédéfini.

0 votes

Il est intéressant de noter que la réponse acceptée fournit un exemple : "%cat% really needs some %beverage%."; n'est-ce pas % séparées dans un format prédéfini ? Votre premier point est encore plus drôle, le JDK fournit un grand nombre de "vieilles fonctionnalités", dont certaines datent des années 90, pourquoi les gens s'embêtent-ils à les utiliser ? Vos commentaires et vos votes négatifs n'ont aucun sens.

0 votes

Quel est l'intérêt d'introduire le moteur de template Rythm alors qu'il existe déjà de nombreux moteurs de template préexistants, et largement utilisés comme Velocity ou Freemarker en plus ? De même, pourquoi introduire un autre produit alors que les fonctionnalités de base de Java suffisent amplement. Je doute vraiment de votre affirmation sur les performances car Pattern peut aussi être compilé. J'aimerais bien voir des chiffres réels.

1voto

Avi Points 14468

Pourquoi ne pas utiliser le replaceAll() méthode ?

4 votes

De nombreuses sous-chaînes différentes peuvent être traitées dans une expression rationnelle (/sous-chaîne1|sous-chaîne2|.../). Tout dépend du type de remplacement que l'OP essaie de faire.

5 votes

L'OP recherche quelque chose de plus efficace que str.replaceAll(search1, replace1).replaceAll(search2, replace2).replaceAll(search3, replace3).replaceAll(search4, replace4)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X