web-dev-qa-db-fra.com

Couper un préfixe possible d'une chaîne en Java

J'ai String str, à partir duquel je veux extraire la sous-chaîne en excluant un préfixe possible "abc".

La première solution qui me vient à l’esprit est la suivante:

if (str.startsWith("abc"))
    return str.substring("abc".length());
return str;

Mes questions sont:

  1. Existe-t-il une méthode plus "propre" pour le faire en utilisant split et une expression régulière pour un "abc"prefix?

  2. Si oui, est-ce moins efficace que la méthode ci-dessus (parce qu'il cherche "tout au long" de la chaîne)?

  3. Si oui, y a-t-il une meilleure façon de le faire (où "meilleure façon" = solution propre et efficace)?

Veuillez noter que le préfixe "abc" peut apparaître ailleurs dans la chaîne et ne doit pas être supprimé.

Merci

26
barak manos

Le code plus court que ci-dessus sera cette ligne:

return str.replaceFirst("^abc", "");

Mais en termes de performances, je suppose qu’il n’y aura pas de différence substantielle entre 2 codes. On utilise regex et on n'utilise pas regex mais recherche et sous-chaîne.

36
anubhava

Utilisation de String.replaceFirst avec ^abc (pour faire correspondre la abc principale)

"abcdef".replaceFirst("^abc", "")     // => "def"
"123456".replaceFirst("^abc", "")     // => "123456"
"123abc456".replaceFirst("^abc", "")  // => "123abc456"
5
falsetru
  1. Utiliser String#split peut le faire, mais ce n’est pas une meilleure solution. En fait, ce sera vague et je ne recommanderais pas de l'utiliser à cette fin.
  2. Ne perdez pas de temps sur l'efficacité dans ce cas, ce n'est pas important, concentrez-vous sur la logique et la clarté. Cependant, notez que travailler avec regex est généralement plus lent, car il implique des opérations supplémentaires. Par conséquent, vous souhaiterez peut-être conserver startsWith.
  3. Votre approche est correcte si vous voulez vérifier si la chaîne commence par "abc", String#startsWith a été conçu pour cela.

Vous pouvez facilement mesurer le temps nécessaire à l'exécution d'un code. Voici ce que vous pouvez faire:

Créez une grande boucle, à l'intérieur de celle-ci, vous pouvez en ajouter le compteur à une chaîne fictive afin de simuler les chaînes que vous souhaitez vérifier, puis essayez d'avoir startsWith une fois et replaceAll après:

for(int i = 0;i<900000;i++) {
    StringBuilder sb = new StringBuilder("abc");
    sb.append(i);
    if(sb.toString().startsWith("abc")) { ... } 
}
long time = System.currentTimeMillis() - start;
System.out.println(time); //Prints ~130

for(int i = 0;i<900000;i++){
   StringBuilder sb = new StringBuilder("abc");
   sb.append(i);
   sb.toString().replaceAll("^abc", "");        
}
long time = System.currentTimeMillis() - start;
System.out.println(time);  //Prints ~730
1
Maroun

Essaye ça

str = str.replaceAll("^abc", "");
1
Evgeniy Dorofeev

Une solution sans regex (j'avais besoin de cela car la chaîne que je supprime est configurable et contient des barres obliques inverses, qui doivent être échappées pour une utilisation littérale dans une regex):

Apache Commons Lang StringUtils.removeStart(str, remove) supprimera remove du début de str en utilisant String.startsWith et String.substring

Le code source de la méthode est informatif:

public static String removeStart(final String str, final String remove) {
    if (isEmpty(str) || isEmpty(remove)) {
        return str;
    }
    if (str.startsWith(remove)){
        return str.substring(remove.length());
    }
    return str;
}
1
mseebach

Si les performances vous préoccupent, vous pouvez améliorer la solution str.replaceFirst("^abc", "") en utilisant le même préfixe précompilé Pattern pour faire correspondre plusieurs chaînes.

final Pattern prefix = Pattern.compile("^abc"); // Could be static constant etc
for ... {
    final String result = prefix.matcher(str).replaceFirst("");
}

Je suppose que la différence sera perceptible si vous supprimez le même préfixe de nombreuses chaînes.

0
Sokolov