サマリ
Javaで文字コード変換してハッシュやBase64エンコードする方法の説明。
結論としては以下のようにすればよい。
例)"文字列"をSJISとしてBase64エンコードする場合
Base64.getEncoder().encodeToString("文字列".getBytes("SJIS"));
目的
-「文字列をSJISに変換してハッシュ化」という要求に対して以下のような頓珍漢なことをしてしまった。
new String("文字列".getBytes("UTF-16"), "SJIS")
- JavaのStringでの文字コードの扱いについて以外にわかっていなかったので整理。
本文
勘違いしていた実行例
<プログラム>
//文字コードをSJISに変換
String sjisString = new String("文字列".getBytes("UTF_16"), "SJIS");
System.out.println("SJISに変換した文字列:");
System.out.println(sjisString);
//SJISに変換した文字列をBase64にエンコード
String base64String = Base64.getEncoder().encodeToString(sjisString.getBytes());
System.out.println("Base64エンコードした文字列:");
System.out.println(base64String);
<実行結果>
SJISに変換した文字列:
��e�[WR
Base64エンコードした文字列:
77+977+9Ze+/vVtXUhc=
「文字列をSJISに変換してハッシュ化」の要求に対し、このロジックにしたのは以下のように考えたため。
①Javaの中では文字列はUTF-16で扱われている。
↓
②まずは文字列をUTF-16からSJISに変換する必要がある。
↓
③SJISに変換した文字列をBase64にエンコードすればよい。
SJISに変換したつもりの文字列を標準出力すると文字化けしているのは、「SJISの文字列をUTF-8で表示されているからかな?」とおかしな納得をしていた。
勘違いのポイント
最初の1行目。
//文字コードをSJISに変換
String sjisString = new String("文字列".getBytes("UTF_16"), "SJIS");
これはUTF-16からSJISに文字コードを変換するわけではなく、以下の動作をする。
-
"文字列".getBytes("UTF_16")
で"文字列"をUTF-16のバイト配列にエンコード -
new String("文字列".getBytes("UTF_16"), "SJIS")
でUTF-16でエンコードされたバイト配列をSJISの文字コードで文字列に復元
異なる文字コードで復元しているので文字化けして当然である。
まとめ
String#getBytes(Charset charset)は文字列を指定された文字コードに変換してくれる。
同じ"文字列"でも指定する文字コードによって結果は以下のように変わる。
<プログラム>
byte[] utf16 = "文字列".getBytes("UTF-16");
byte[] utf8 = "文字列".getBytes("UTF-8");
byte[] sjis = "文字列".getBytes("SJIS");
System.out.println("UTF-16 :" + Arrays.toString(utf16));
System.out.println("UTF-8 :" + Arrays.toString(utf8));
System.out.println("SJIS :" + Arrays.toString(sjis));
<実行結果>
UTF-16 :[-2, -1, 101, -121, 91, 87, 82, 23]
UTF-8 :[-26, -106, -121, -27, -83, -105, -27, -120, -105]
SJIS :[-107, -74, -114, -102, -105, -15]
冒頭に記載したBase64エンコードやハッシュ化のメソッドは引数にbyte[]をとるようになっている。
このため、上記のとおり文字列を希望の文字コードでgetBytes()して、各メソッドの入力にすればよかった。
Base64.getEncoder()#encode(byte[] src)
DigestUtils#digest(byte[] data)
わかってしまえばとても初歩的な話だが、一度勘違いしてしまうと、なかなか気が付けなかった。
参考にさせていただいたページ
いいから聞け! 俺が文字コードについて教えてやるよ その2(Javaの文字コード編)
https://cero-t.hatenadiary.jp/entry/20110621/1308667569