41
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CamelCase と snake_case を相互変換する

Last updated at Posted at 2015-12-23

背景

「Java で CamelCase(単語の区切りで大文字にする記法)と snake_case(単語の区切りで_を使って連結する記法)を相互変換するにはどうしたらよいか?」という話題が会社で出ました。Java の標準ライブラリにはこの機能がないので、意外に必要とされないのでしょうか?

CaseFormat

調べてみたところ、Google Guava にこの変換をやるためのクラス CaseFormat があることを知りました。元の文字列のフォーマットを指定して、to メソッドで変換先のフォーマットを指定する、という感じで使うようです。なお、今回私の言う snake_case は LOWER_UNDERSCORE という名前になっています。

CamelCase から snake_case への変換は下記のコードで可能です。

final String snake = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "TomatoCurry");

逆に、snake_case から CamelCase への変換は下記の通りです。

final String camel = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "tomato_curry");

簡単でわかりやすいですね。Guava はライセンスも Apache License 2.0 ですし、通常はこちらを使っておけば間違いないでしょう。


自作してみる

ただ、1機能を使いたいためだけに Guava を導入するのも何だと思ったので、自分で似た機能を勉強も兼ねて実装してみました。

ソースコード

全体はこちら

camelToSnake()
    public static final String camelToSnake(final String camel) {
        if (StringUtils.isEmpty(camel)) {
            return camel;
        }
        final StringBuilder sb = new StringBuilder(camel.length() + camel.length());
        for (int i = 0; i < camel.length(); i++) {
            final char c = camel.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(sb.length() != 0 ? '_' : "").append(Character.toLowerCase(c));
            } else {
                sb.append(Character.toLowerCase(c));
            }
        }
        return sb.toString();
    }
snakeToCamel()
    public static final String snakeToCamel(final String snake) {
        if (StringUtils.isEmpty(snake)) {
            return snake;
        }
        final StringBuilder sb = new StringBuilder(snake.length() + snake.length());
        for (int i = 0; i < snake.length(); i++) {
            final char c = snake.charAt(i);
            if (c == '_') {
                sb.append((i + 1) < snake.length() ? Character.toUpperCase(snake.charAt(++i)) : "");
            } else {
                sb.append(sb.length() == 0 ? Character.toUpperCase(c) : Character.toLowerCase(c));
            }
        }
        return sb.toString();
    }

渡された文字列を1字1字見て、変換対象の文字列があったら処理をして StringBuilder に append し、最後に新しい文字列オブジェクトを生成して返す、という単純な処理をするメソッドです。


比較・検証

せっかくなので実行速度を計測してみることにしました。検証用のコードはこちらです。なお、Collection フレームワークには GS Collections を使いました。

Method Average time[ms]
Guava 450.2
CharAt 277.0
Array 225.6

自作の方は雑な機能しかない分だけ速く実行できているようです。


【追記】 JMH でのパフォーマンスチェック

その後、Java のコードのパフォーマンスチェックは JMH を使うべきだと知りましたので、改めて JMH でやり直しました。

修正差分

JMH を使うための修正差分は下記の commit をご覧ください。

実行環境

Key Value
Java SE 1.8.0_u121
JMH 1.18
Gradle 3.4.1
OS Windows 10
CPU Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz 2.90 GHz
RAM 16.0GB

JMH の設定

Key Value
jmhVersion 1.18
warmupIterations 5
iterations 20
fork 2
benchmarkMode ['thrpt']
failOnError true

実行結果

# Run complete. Total time: 00:02:40

Benchmark                           Mode  Cnt   Score   Error   Units
SnakeCamelBenchmark.convertGuava   thrpt   40  32.391 ± 6.586  ops/ms
SnakeCamelBenchmark.convertCharAt  thrpt   40  37.823 ± 4.994  ops/ms
SnakeCamelBenchmark.convertArray   thrpt   40  27.984 ± 2.503  ops/ms

結論

Guava の CaseFormat クラスを使いましょう。

GitHub repository

41
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?