Le lien direct pour
retrouver cet article est:
web/actualites/actualites/fill-zero
Une problématique se
présente souvent aux développeurs:
Comment afficher un
nombre (en général, un identifiant) sur un certain nombre de
caractères et de remplir avec des zéros les caractères vides?
Exemple:
Afficher 35 sur 6
caractères.
On doit obtenir
« 000035 ».
La méthode est connue
dans le monde du développement sous l'anglicisme de « fillZero ».
D'ailleurs nous avons eu
besoin d'une méthode fillZero dans GenericSystem pour ordonner des
identifiants, comme par exemple numéroter les tâches dans notre
tracker de bug.
Nous avons envisagé
différents méthodes que je vais maintenant vous présenter.
Méthode
« mathématique ».
public
String fillZero(long
i, int
length){
return
Long.toString(i+Double.valueOf(Math.pow(10,length)).longValue()).substring(1);
}
Méthode
« DecimalFormat ».
(Limité
au nombre de 0 dans la chaîne "00000000000000000000")
public
String fillZero(long
i, int
length){//length max 20
return
new
DecimalFormat("00000000000000000000".substring(0,length)).format(i);
}
Méthode
« récursive ».
public
String fillZero(long
i, int
length){
return
(length>Long.toString(i).length())?"0"+fillZero(i,length-1):Long.toString(i);
}
Certaines
méthodes trouvées par nos développeurs nécessitaient une méthode
commune permettant d'éviter que la méthode se bloque quand on
arrive au nombre maximum.
Mais
cela-là peut nuire à la vitesse d'exécution de la méthode. Donc
dans le benchmark, il y aura le résultat sécurisé et le résultat
non sécurisé.
Méthode
de sécurisation.
private
int
securedLength(long
i, int
length) {
return
(length>Long.toString(i).length())?(length
- Long.toString(i).length()):0;
}
Méthode
« StringReplace ».
public
static
String fillZero(long
i, int
length) {
return
new
String(
new
char[length
- Long.toString(i).length()])
.replace((char)0,
'0') +
Long.toString(i);
}
Méthode
« StringReplace » sécurisée.
public
static
String fillZero(long
i, int
length) {
return
new
String(
new
char[securedLength(i,
length)])
.replace((char)0,
'0') +
Long.toString(i);
}
Méthode « récursive
terminale ».
public
String fillZero(long
i, int
length) {
return
letFillZero(new
char[length
- Long.toString(i).length()],
0, Long.toString(i));
}
private
String letFillZero (char[]
array, int
i, String value) {
if
(i < array.length)
{
array[i]
= '0';
return
letFillZero(array,
i + 1, value);
}
return
new
String(array) + value;
}
Méthode
« récursive terminale » sécurisée.
public
String fillZero(long
i, int
length) {
return
letFillZero(new
char[securedLength(i,
length)], 0, Long.toString(i));
}
Méthode
« Boucle itérative » .
public
String fillZero(long nb, int
length){
StringBuffer
sb = new
StringBuffer();
for
(int
i = 0; i < (length-Long.toString(nb).length());
i++)sb.append("0");
return
sb.append(nb).toString();
}
Méthode
« SubString » .
(Limité
au nombre de 0 dans la chaîne "00000000000000000000")
public
String UfillZero(long
i, int
length){ //length max 20
return
"00000000000000000000".substring(0,
length - Long.toString(i).length())+i;
}
Méthode
« SubString » sécurisée.
(Limité
au nombre de 0 dans la chaîne "00000000000000000000")
public
String fillZero(long i, int
length){ //length max 20
return
"00000000000000000000".substring(0,
securedLength(i,
length))+i;
}
Méthode
« org.apache.commons.lang.StringUtils ».
public
String fillZero(long
value, int
length) {
return
StringUtils.leftPad(String.valueOf(value),
length, "0");
}
Condition
du BENCHMARK
Nous
avons utilisé une méthode assez simple. Nous avons chronométré le
temps d'exécution des méthodes et fait la moyenne sur 10 appels de
la méthode.
Le
test est le suivant:
Exécuter
fillZero pour tous les nombres allant de 0 à 999999 avec affichage
sur 6 caractères.
Résultat
du BENCHMARK
La
deuxième colonne présente les résultats non sécurisés (avec
1000000 au lieu de 999999 une exception est levée).
Les
résultats sont en seconde à la milliseconde près.
|
Nicolas
Mathématique
|
1.2202
|
|
|
Guillaume
Récursif
|
0.5664
|
|
|
Mathieu
StringReplace
|
1.0067
|
0.9885
|
|
Mathieu
Récursif
|
0.9478
|
0.9311
|
|
Aurélien
Boucle
|
0.7752
|
|
|
Romain
SubString
|
0.7871
|
0.75869995
|
|
Oussama
DecimalFormat
|
9.2834
|
|
|
Mickael
Commons-Lang
|
1.2169001
|
|
La méthode récursive est
plus rapide et de plus le code est assez simple.
Cette méthode a donc été
incluse dans le code de GenericSystem.
Cf Tâche GS1435
GGT
Mise à jour:
« adiguba »
sur le forum de Developpez.com
a proposé une méthode encore plus rapide pour faire un fillZero.
Méthode
« Arrays.fill » .
Public
String fillZero(long
i, int
length) {
//
On convertit
en
String de
manière tout à fait
normale :
String
str = Long.toString(i);
final
int
strLen = str.length();
//
Si
la chaîne est plus courte
que la taille voulue
if
(strLen<length) {
//
On crée
un nouveau buffer à la
taille voulue :
final
char[]
cbuf = new
char[length];
//
On
remplace les éléments
manquants par des
zéros :
Arrays.fill(cbuf,
0, length-strLen, '0');
//
Et on recopie
les chars de
la chaîne qu'on a créé
:
str.getChars(0,
strLen, cbuf, length-strLen);
//
Juste
avant de
recrééer une nouvelle String :
str
= new
String(cbuf);
}
return
str;
}
Je
me suis empressé de refaire le benchmark et le résultat ne laisse
aucune place au doute.
Cette
méthode est deux fois plus rapide que la méthode récursive.
|
Nicolas
Mathématique
|
1.2385
|
|
|
Guillaume
Récursif
|
0.5832
|
|
|
Mathieu
StringReplace
|
1.0213
|
0.9964
|
|
Mathieu
Récursif
|
0.9795
|
0.9396
|
|
Aurélien
Boucle
|
0.7958
|
|
|
Romain
SubString
|
0.8126
|
0.7793
|
|
Oussama
DecimalFormat
|
9.5709
|
|
|
Mickael
Commons-Lang
|
1.2592
|
|
|
adiGuba
ArraysFill
|
0.2892
|
|