Quel est le moyen le plus efficace de rendre le premier caractère d'un String
minuscule?
Je peux penser à un certain nombre de façons de le faire:
Utilisation de charAt()
avec substring()
String input = "SomeInputString";
String output = Character.toLowerCase(input.charAt(0)) +
(input.length() > 1 ? input.substring(1) : "");
Ou en utilisant un tableau char
String input = "SomeInputString";
char c[] = input.toCharArray();
c[0] = Character.toLowerCase(c[0]);
String output = new String(c);
Je suis convaincu qu'il existe de nombreux autres moyens de parvenir à cela. Que recommandez-vous?
J'ai testé les approches prometteuses en utilisant JMH . Benchmark complet code .
Hypothèse pendant les tests (pour éviter de vérifier chaque casse dans les angles): la longueur de la chaîne entrée est toujours supérieure à 1.
Benchmark Mode Cnt Score Error Units
MyBenchmark.test1 thrpt 20 10463220.493 ± 288805.068 ops/s
MyBenchmark.test2 thrpt 20 14730158.709 ± 530444.444 ops/s
MyBenchmark.test3 thrpt 20 16079551.751 ± 56884.357 ops/s
MyBenchmark.test4 thrpt 20 9762578.446 ± 584316.582 ops/s
MyBenchmark.test5 thrpt 20 6093216.066 ± 180062.872 ops/s
MyBenchmark.test6 thrpt 20 2104102.578 ± 18705.805 ops/s
Les points sont exprimés en opérations par seconde, mieux c'est.
test1
Fut la première approche d'Andy et Hllink:
string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
test2
Était la seconde approche d'Andy. C'est aussi Introspector.decapitalize()
suggéré par Daniel, mais sans deux déclarations if
. Le premier if
a été supprimé en raison de l'hypothèse de test. Le second a été supprimé, car il violait la correction (c’est-à-dire que l’entrée "HI"
Renverrait "HI"
). C'était presque le plus rapide.
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
string = new String(c);
test3
Était une modification de test2
, Mais au lieu de Character.toLowerCase()
, j’en ajoutais 32, ce qui fonctionne correctement si et seulement si la chaîne est en ASCII. C'était le plus rapide. c[0] |= ' '
De Mike comment a donné la même performance.
char c[] = string.toCharArray();
c[0] += 32;
string = new String(c);
test4
Utilisé StringBuilder
.
StringBuilder sb = new StringBuilder(string);
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
string = sb.toString();
test5
A utilisé deux appels substring()
.
string = string.substring(0, 1).toLowerCase() + string.substring(1);
test6
Utilise la réflexion pour changer char value[]
directement dans String. C'était le plus lent.
try {
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[]) field.get(string);
value[0] = Character.toLowerCase(value[0]);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
Si la longueur de la chaîne est toujours supérieure à 0, utilisez test2
.
Sinon, nous devons vérifier les cas de coin:
public static String decapitalize(String string)
if (string == null || string.length() == 0) {
return string;
}
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
return new String(c);
}
Si vous êtes sûr que votre texte sera toujours dans ASCII et que vous recherchez des performances extrêmes car vous avez trouvé ce code dans le goulot d'étranglement, utilisez test3
.
Je suis tombé sur une alternative de Nice si vous ne voulez pas utiliser une bibliothèque tierce:
import Java.beans.Introspector;
Assert.assertEquals("someInputString", Introspector.decapitalize("SomeInputString"));
Pour ce qui est de la manipulation des cordes, jetez un coup d’œil à Jakarta Commons Lang StringUtils .
Si vous souhaitez utiliser Apache Commons, vous pouvez effectuer les opérations suivantes:
import org.Apache.commons.lang3.text.WordUtils;
[...]
String s = "SomeString";
String firstLower = WordUtils.uncapitalize(s);
Résultat: un peu de corde
Malgré une approche orientée caractère, je suggérerais une solution orientée chaîne. String.toLowerCase dépend des paramètres régionaux. Je tiens donc compte de ce problème. String.toLowerCase
est préférable pour les minuscules selon Character.toLowerCase . De plus, une solution orientée caractères n'est pas totalement compatible Unicode, car Character.toLowerCase ne peut pas gérer les caractères supplémentaires.
public static final String uncapitalize(final String originalStr,
final Locale locale) {
final int splitIndex = 1;
final String result;
if (originalStr.isEmpty()) {
result = originalStr;
} else {
final String first = originalStr.substring(0, splitIndex).toLowerCase(
locale);
final String rest = originalStr.substring(splitIndex);
final StringBuilder uncapStr = new StringBuilder(first).append(rest);
result = uncapStr.toString();
}
return result;
}
UPDATE: Par exemple, l’importance des paramètres régionaux est minuscule I
en turc et en allemand:
System.out.println(uncapitalize("I", new Locale("TR","tr")));
System.out.println(uncapitalize("I", new Locale("DE","de")));
produira deux résultats différents:
je
je
Les chaînes entre Java étant immuables, une nouvelle chaîne sera créée dans tous les cas.
Votre premier exemple sera probablement un peu plus efficace, car il lui suffit de créer une nouvelle chaîne et non un tableau de caractères temporaire.
Une méthode statique très courte et simple pour archiver ce que vous voulez:
public static String decapitalizeString(String string) {
return string == null || string.isEmpty() ? "" : Character.toLowerCase(string.charAt(0)) + string.substring(1);
}
Si ce dont vous avez besoin est très simple (par exemple. Java, pas de paramètres régionaux)), vous pouvez également utiliser le CaseFormat dans la bibliothèque de Google Guava .
String converted = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, "FooBar");
assertEquals("fooBar", converted);
Vous pouvez également préparer et réutiliser un objet convertisseur, ce qui pourrait être plus efficace.
Converter<String, String> converter=
CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_CAMEL);
assertEquals("fooBar", converter.convert("FooBar"));
Pour mieux comprendre la philosophie de la manipulation des chaînes de Google Guava, consultez cette page de wiki .
Je suis venu à travers cela seulement aujourd'hui. J'ai essayé de le faire moi-même de la manière la plus piétonne. Cela a pris une ligne, bien longish. Voici
String str = "TaxoRank";
System.out.println(" Before str = " + str);
str = str.replaceFirst(str.substring(0,1), str.substring(0,1).toLowerCase());
System.out.println(" After str = " + str);
Donne:
Avant str = TaxoRanks
Après str = taxoRanks
String testString = "SomeInputString";
String firstLetter = testString.substring(0,1).toLowerCase();
String restLetters = testString.substring(1);
String resultString = firstLetter + restLetters;
val str = "Hello"
s"${str.head.toLower}${str.tail}"
Résultat:
res4: String = hello