0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Javaのプロパティファイルのエスケープを使用したい

Last updated at Posted at 2024-07-11

Javaのプロパティファイルのエスケープが欲しい

仕事でいくつかの顧客のためのデプロイをする際に設定ファイルを文字列置換ツールを自分で作って使っているのですが、propertiesファイルの値に日本語を入れる必要が生じたときに通常の文字列変換だけやってテキストファイル書き込みをやってしまうと例の

日本語 -> \u65E5\u672C\u8A9E

にならなくてなにか面倒になるかもしれないと思って使えそうなものを色々と調べました。
Apache Commons の org.apache.commons.text.StringEscapeUtils クラスの以下のメソッドが

static String escapeJava(String input)
static String unescapeJava(String input)

多バイト文字の問題は解決してくれるのですが、java propertiesファイルはシングルバイトの特殊文字もいくつかエスケープしますし、どの特殊文字がエスケープされるのかを調べるのも面倒だし間違えそうなので、java.util.Properties クラスを使って文字列エスケープをすれば間違いないと思い以下のコードを書きました。

Javaソースコード
PropertiesEscaping.java
package com.example.properties;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;

public class PropertiesEscaping {

	private static final String KEY = "__key__";
	private static final String KEY_AND_EQ = KEY + "=";

	// エスケープメソッド
	public static String escape(String input) {
		String value = null;
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			Properties prop = new Properties();
			prop.setProperty(KEY, input);	// propertiesに値をセット
			prop.store(bos, null);	// ストリームに書き出して
			byte[] bytes = bos.toByteArray();	// バイト列を取得
			String content = new String(bytes);	// バイト列を文字列に
			String[] lines = content.split("\n");	// propertiesファイルそのものなので...
			for (String line : lines) {
				if (line.startsWith(KEY_AND_EQ)) {
    				// 目的の行が見つかったのでキーとイコールを省く
					value = line.substring(KEY_AND_EQ.length());
					break;	// 目的の文字列をゲット
				}
			}

			bos.close();	// 閉じておきましょう
		}
		catch (IOException ex) {
			ex.printStackTrace(System.err);
			value = null;	// エラーなので念の為...
		}

		return value;
	}

	// アンエスケープメソッド
	public static String unescape(String input) {
		String value = null;
		String content = KEY_AND_EQ + input;	// キー&バリューの一行
		try {
			// バイト変換してストリームにセット
			ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes());
			Properties prop = new Properties();
			prop.load(bis);	// バイトストリームをPropertiesに読み込ませ
			value = prop.getProperty(KEY);	// 目的の文字列をゲット

			bis.close();	// 閉じておきましょう
		}
		catch (Exception ex) {
			ex.printStackTrace(System.err);
			value = null;	// エラーなので念の為...
		}
		return value;
	}

	// メイン
	public static void main(String[] args) {
		String val1 = "~!@#$%^&*()_+`-=|[{}]\\:\";'<>?,./ 日本語 Qiita";
		String val2 = escape(val1);
		String val3 = unescape(val2);
		System.out.println("val1: " + val1);
		System.out.println("val2: " + val2);
		System.out.println("val3: " + val3);
	}
}

コードで書くと上記のような簡単なものになります。
説明はコメントの通りです。

コンパイルと実行
$ javac com/example/properties/PropertiesEscaping.java
$ java -cp . com.example.properties.PropertiesEscaping
val1: ~!@#$%^&*()_+`-=|[{}]\:";'<>?,./ 日本語 Qiita
val2: ~\!@\#$%^&*()_+`-\=|[{}]\\\:";'<>?,./ \u65E5\u672C\u8A9E Qiita
val3: ~!@#$%^&*()_+`-=|[{}]\:";'<>?,./ 日本語 Qiita

必要だったのはescapeメソッドだけでしたが、unescapeメソッドも作ってみました。
unescapeメソッドは必要なシーンがちょっと思い浮かびませんね。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?