web-dev-qa-db-ja.com

文字列の最初の文字を小文字にする最も効率的な方法は?

Stringの最初の文字を小文字にする最も効率的な方法は何ですか?

これを行うにはいくつかの方法が考えられます。

_charAt()substring()の使用

String input   = "SomeInputString";
String output  = Character.toLowerCase(input.charAt(0)) +
                   (input.length() > 1 ? input.substring(1) : "");

またはchar配列を使用(

 String input  = "SomeInputString";
 char c[]      = input.toCharArray();
 c[0]          = Character.toLowerCase(c[0]);
 String output = new String(c);

私はこれを達成するための多くの他の素晴らしい方法があると確信しています。何がお勧めですか?

90
Andy

[〜#〜] jmh [〜#〜] を使用して、有望なアプローチをテストしました。完全なベンチマーク コード

テスト中の仮定(毎回コーナーケースをチェックしないようにするため):入力文字列の長さは常に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
_

スコアは1秒あたりの操作数で、多ければ多いほど良いです。

テスト

  1. _test1_は最初のAndyとHllinkのアプローチでした:

    _string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
    _
  2. _test2_は2番目のAndyのアプローチでした。また、ダニエルによって提案された Introspector.decapitalize() ですが、2つのifステートメントはありません。最初のifは、テストの前提のため削除されました。 2番目のものは、正確性に違反していたため削除されました(つまり、入力_"HI"_は_"HI"_を返します)。これはほぼ最速でした。

    _char c[] = string.toCharArray();
    c[0] = Character.toLowerCase(c[0]);
    string = new String(c);
    _
  3. _test3_は_test2_の修正ですが、Character.toLowerCase()の代わりに32を追加しました。これは、文字列がASCIIである場合にのみ正しく動作します。これが最速でした。マイクの コメント の_c[0] |= ' '_は同じパフォーマンスを示しました。

    _char c[] = string.toCharArray();
    c[0] += 32;
    string = new String(c);
    _
  4. _test4_使用済みStringBuilder

    _StringBuilder sb = new StringBuilder(string);
    sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
    string = sb.toString();
    _
  5. _test5_は2つのsubstring()呼び出しを使用しました。

    _string = string.substring(0, 1).toLowerCase() + string.substring(1);
    _
  6. _test6_はリフレクションを使用して、Stringで直接 _char value[]_ を変更します。これが最も遅かった。

    _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();
    }
    _

結論

文字列の長さが常に0より大きい場合は、_test2_を使用します。

そうでない場合は、コーナーケースを確認する必要があります。

_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);
}
_

テキストが常にASCIIであることが確実であり、このコードがボトルネックにあるために極端なパフォーマンスを探している場合は、_test3_を使用してください。

110

サードパーティのライブラリを使用したくない場合は、素敵な代替手段に出くわしました:

import Java.beans.Introspector;

Assert.assertEquals("someInputString", Introspector.decapitalize("SomeInputString"));
89
Daniel Pacak

文字列操作に関しては、ジャカルタコモンズラング StringUtils をご覧ください。

20
Carlos Tasada

Apache Commonsを使用する場合は、次のことができます。

import org.Apache.commons.lang3.text.WordUtils;
[...] 
String s = "SomeString"; 
String firstLower = WordUtils.uncapitalize(s);

結果:someString

14
Sebastian

文字指向のアプローチにもかかわらず、文字列指向のソリューションを提案します。 String.toLowerCase はロケール固有であるため、この問題を考慮します。 String.toLowerCaseは、 Character.toLowerCase に従って小文字を優先することです。 Character.toLowerCase は補助文字を処理できないため、char指向のソリューションは完全なUnicode互換ではありません。

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:例として、ロケール設定がトルコ語とドイツ語で小文字のIを使用することの重要性を示します。

System.out.println(uncapitalize("I", new Locale("TR","tr")));
System.out.println(uncapitalize("I", new Locale("DE","de")));

2つの異なる結果を出力します。

10

Javaの文字列は不変なので、どちらの方法でも新しい文字列が作成されます。

最初の例は、一時的な文字配列ではなく、新しい文字列を作成するだけでよいため、おそらくわずかに効率的です。

7
Alan Geleynse

必要なものをアーカイブするための非常に短く簡単な静的メソッド:

public static String decapitalizeString(String string) {
    return string == null || string.isEmpty() ? "" : Character.toLowerCase(string.charAt(0)) + string.substring(1);
}
3
Hllink

必要なものが非常に単純な場合(例:Javaクラス名、ロケールなし)、 CaseFormatGoogle Guava ライブラリのクラス。

String converted = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, "FooBar");
assertEquals("fooBar", converted);

または、コンバータオブジェクトを準備して再利用することもできますが、これはより効率的です。

Converter<String, String> converter=
    CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_CAMEL);

assertEquals("fooBar", converter.convert("FooBar"));

Google Guava文字列操作の哲学をよりよく理解するには、 このwikiページ をチェックしてください。

2
Peter Lamberg

私は今日だけこれに出くわしました。最も歩行者的な方法でそれを自分でやろうとしました。それには長い行が必要でした。ここに行く

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);

与える:

Str = TaxoRanksの前

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}"

結果:

res4: String = hello
1
Vivek