Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

キャメルケース表記を正規表現でアンダースコア区切り表記に変換

Javaでキャメルケース表記をスネークケース(アンダースコア区切り)表記に変換するには、そしてその逆に変換するにはどうすればいいか?という話。
RoRのcamelizeやunderscoreに近いのでinflector.rbを移植するのが間違いなく速く正確だろうと思いつつも、自前で考えてみました。

キャメルケース表記をスネークケース表記へ

変換ルールは以下の通りです。基本的なスタンスとしては小文字と大文字の間にアンダースコアを挿入します。それだけだと変換対象文字に大文字が連続していた場合(CSVReaderやHogeDAOなど)に正しく変換できませんので、連続する大文字を単語として認識する必要があります。
大文字の連続はキャメルケースとして例外ではありますが、Javaのライブラリでもたまに見かけるので対応したほうがいいと判断しました。

  • 小文字と大文字の境を単語の境界として認識
  • 単語の境界にアンダースコアを挿入
  • 行末でない場所に大文字が連続する場合は最後の1文字を除き、単語として認識(「DTOClass」は「DTO」「Class」に分ける)

	// キャメルケース表記をスネークケース表記(小文字)へ
	public static String camelToSnake(String targetStr) {
		String convertedStr = targetStr
				.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2")
				.replaceAll("([a-z])([A-Z])", "$1_$2");
		return convertedStr.toLowerCase();
	}

スネークケース表記をローワーキャメルケース表記へ

こちらの変換ルールは単純で、アンダースコアに続く英字を大文字に変換します。アッパーキャメルケースならば最初の英字も大文字に変換すれば良いでしょう。
replaceAllメソッドでは小文字を大文字に変換する方法が見つかっていないので、Matcherクラスによる変換を利用しています。そのためコードは長くなっていますが、やっていることはとても単純です。

  • アンダースコアにつづく英字を大文字に変換し、アンダースコアを消去
  • それ以外の文字列を小文字に変換

	// スネークケース表記をローワーキャメルケース表記へ
	public static String snakeToCamel(String targetStr) {
		Pattern p = Pattern.compile("_([a-z])");
		Matcher m = p.matcher(targetStr.toLowerCase());

		StringBuffer sb = new StringBuffer(targetStr.length());
		while (m.find()) {
			m.appendReplacement(sb, m.group(1).toUpperCase());
		}
		m.appendTail(sb);
		return sb.toString();
	}

追記:ライブラリを使う場合

GuavaにあるCaseFormatクラスが使えます。