web-dev-qa-db-fra.com

Le moyen le plus efficace de faire le premier caractère d’une minuscule String?

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?

90
Andy

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.

Résultats

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.

Des tests

  1. test1 Fut la première approche d'Andy et Hllink:

    string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
    
  2. 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);
    
  3. 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);
    
  4. test4 Utilisé StringBuilder.

    StringBuilder sb = new StringBuilder(string);
    sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
    string = sb.toString();
    
  5. test5 A utilisé deux appels substring().

    string = string.substring(0, 1).toLowerCase() + string.substring(1);
    
  6. 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();
    }
    

Conclusions

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.

110
Adam Stelmaszczyk

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"));
89
Daniel Pacak

Pour ce qui est de la manipulation des cordes, jetez un coup d’œil à Jakarta Commons Lang StringUtils .

20
Carlos Tasada

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

14
Sebastian

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

10
Michael Konietzka

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.

7
Alan Geleynse

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);
}
3
Hllink

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 .

2
Peter Lamberg

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

1
user3501758
String testString = "SomeInputString";
String firstLetter = testString.substring(0,1).toLowerCase();
String restLetters = testString.substring(1);
String resultString = firstLetter + restLetters;
1
Bae Cheol Shin
val str = "Hello"
s"${str.head.toLower}${str.tail}"

Résultat:

res4: String = hello
1
Vivek