Java における文字列とバイナリ列の相互変換についてと OAuth のパーセントエンコードの方法
Java で文字列を扱うのはあまり慣れておらず、文字列をパーセントエンコードするのにちょっとてこずったので軽くメモを。
文字列 (String
オブジェクト) とバイナリ列 (byte
型配列) の相互変換
Java において、文字列を任意のエンコーディングでエンコードしてバイナリ列を得るには、String#getBytes( Charset )
メソッド を使用します。
// "あいうえお" という文字列が UTF-8 エンコードされたバイナリ列 byte[] encodedStr = "あいうえお".getBytes( Charset.forName( "UTF-8" ) );
また、バイナリ列 (byte
型配列) を文字列に戻す場合には、String
クラスのコンストラクタ String( byte[], Charset )
を使用します。
String str = new String( encodedStr, Charset.forName( "UTF-8" ) );
パーセントエンコード (The OAuth 1.0 Protocol 仕様)
The OAuth 1.0 Protocol (RFC5849) の仕様に合うように、文字列をパーセントエンコードします。 パーセントエンコードというのは、URL エンコードに用いられるように、エスケープすべき文字がある場合に、そのバイナリ列を 1 バイト毎に '%' + XX
(XX は、バイト値を 16 進数表示したもの) の形式で表現するものです。
文字列をパーセントエンコードするには、まず文字列をエンコードしたバイナリ列を取得し、バイナリ列に対して処理を行います。 バイナリ列の取得は、上で述べた方法でできます。 また、バイナリ列に対して処理を行う際、byte
型の可変長配列が欲しいところですが、java.io.ByteArrayOutputStream
クラス をその用途に用いることができます。
パーセントエンコードを行う機能を提供するクラスのサンプルコードを以下に示します。
package info.vividcode.oauth; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.Charset; /** * The OAuth 1.0 Protocol の仕様に合う形で文字列をパーセントエンコードする * 機能を提供するクラス * @author nobuoka */ public class OAuthEncoder { /** "0123456789ABCDEF" の ASCII バイト列 */ static final private byte[] BS = { 48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70 }; /** 指定のバイトをパーセントエンコードする必要があるかどうかの真理値を格納した配列 * (インデックスがバイト値に対応. ただし最上位ビットが 1 のものは含まない) */ static final private boolean[] NEED_ENCODE = new boolean[ 0x7F ]; // NEED_ENCODING の初期化 static { for( int i = 0; i < NEED_ENCODE.length; i++ ) { // a(97)-z(122), A(65)-Z(90), 0(48)-9(57), -(45), .(46), _(95), ~(126) if( ( 65 <= i && i <= 90 ) || ( 97 <= i && i <= 122) || ( 48 <= i && i <= 57 ) || i == 45 || i == 46 || i == 95 || i == 126 ) { NEED_ENCODE[i] = false; } else { NEED_ENCODE[i] = true; } } } /** * can't instantiate from this class */ private OAuthEncoder() {} /** * The OAuth 1.0 Protocol の仕様に合う形で文字列をパーセントエンコードする. * パーセントエンコードの対象になるのは 'A'-'Z', 'a'-'z', '0'-'9', '-', '.', '_', '~' を除く全ての文字である. * @param str パーセントエンコードの対象文字列 * @return str をパーセントエンコードした文字列 */ static public String encode( String str ) { String encodedStr = null; ByteArrayOutputStream os = null; try { os = new ByteArrayOutputStream(); for( byte b : str.getBytes( Charset.forName( "UTF-8" ) ) ) { if( b < 0 || NEED_ENCODE[b] ) { // "%" os.write( 37 ); // 上の 4 ビット os.write( BS[ ( b >> 4 ) & 0x0F ] ); // 下の 4 ビット os.write( BS[ b & 0x0F ] ); } else { os.write( b ); } } encodedStr = os.toString(); } finally { try { // close する意味はないが, 一応 if( os != null ) os.close(); } catch( IOException err ) { err.printStackTrace(); } } return encodedStr; } }
次のように使うことができます。
String parcentEncodedStr = OAuthEncoder.encode( "あい" ); //=> "%E3%81%82%E3%81%84"