現在、文字コードの変換について行っていて、文字列をバイトに変換する、というのがありました。
package org.jyl.base.io;
import java.util.ArrayList;
import javax.xml.bind.DatatypeConverter;
/**
* Java のプリミティブ型 {@code char} を基に、
* 複数文字コードに対応した単一文字を示すクラスです。
* このクラスでは、Java の仕様上、文字コードとバイトを用いて
* 文字を特定したあと、{@code UTF-16} に変換されます。
*
* @author とあるゆっくり
*/
public class JylChar
{
// 文字コードごとに変換後の対応する char 値
private final char c;
// 文字コード
private final CharCode code;
// 文字を対応する文字コードに変換した際のバイト
private final ArrayList<Byte> charbyte = new ArrayList<Byte>( 0 );
/**
* オブジェクトに文字とエンコードを格納します。
*
* @param c 文字
* @param code エンコードの列挙
*/
public JylChar( char c, CharCode code )
{
// 文字をセット
this.c = c;
// 文字コードを指定
this.code = code;
setByte( this.c );
}
/**
* バイトと文字エンコードから文字を取得します。
*
* @param b 一文字のバイト この中の全てのバイトを用いて文字を決定します。
* ただし、エンコードごとに決められたサイズを超えた場合、切り捨てされることがあります。
* @param code 文字のエンコード
*
* @throws IllegalArgumentException 指定エンコードと指定バイトで文字が決定しなかった場合
*/
public JylChar( byte[] b, CharCode code )
{
// 文字コードを設定
this.code = code;
int loop = 0; // 1 文字のバイト数( 最大 )
if( code == CharCode.ASCII ) loop = 1;
if( code == CharCode.EUC ) loop = 3;
if( code == CharCode.Shift_JIS ) loop = 2;
if( code == CharCode.Unicode ) loop = 4;
if( code == CharCode.UTF_8 ) loop = 6;
if( b.length > loop ){ // 文字を指定するのに必要なバイト数をオーバーした場合
byte[] bys = new byte[ loop ]; // オーバーしたデータを入れられた場合、計算に使われる配列
for( int l = 0; l < bys.length; l++ ) bys[ l ] = b[ l ];
// バイトと文字エンコードから文字を取得
c = setChar( bys );
}else{
c = setChar( b );
}
setByte( c );
}
/**
* 指定したエンコードで指定した文字を出力するためのバイト配列を返します。
*
* @return 指定文字を示すバイト配列
*/
public byte[] getBytes()
{
// 必要数のバイト配列を作成
byte[] by = new byte[ charbyte.size() ];
for( int l = 0; l < charbyte.size(); l++ ){
by[ l ] = charbyte.get( l );
}
return by;
}
/**
* このクラスに格納されている文字を取得します。
*
* @return 格納されている文字 エンコードなどによっては機種依存文字などが含まれる可能性があります。
*/
public char getChar()
{
return c;
}
/**
* この文字の文字コードを返します。
* なお、文字コードを変更することはできません。
*
* @return このオブジェクトの文字コード
*/
public CharCode getCharCode()
{
return code;
}
// private のメゾッド( 公開する必要がない ) 公開するとデータを壊す可能性があるため
// バイトをセットする
private void setByte( char c )
{
String binarydata = ""; // バイトに変換した際のデータを入れる 16 進数データ
switch( c ){
case '0':{
if( code == CharCode.ASCII ) binarydata = "30";
if( code == CharCode.EUC ) binarydata = "A3B0";
if( code == CharCode.Shift_JIS ) binarydata = "824F";
if( code == CharCode.UTF_8 ) binarydata = "EFBC90";
if( code == CharCode.Unicode ) binarydata = "FF10";
break;
}case '1':{
if( code == CharCode.ASCII ) binarydata = "31";
if( code == CharCode.EUC ) binarydata = "A3B1";
if( code == CharCode.Shift_JIS ) binarydata = "8250";
if( code == CharCode.UTF_8 ) binarydata = "EFBC91";
if( code == CharCode.Unicode ) binarydata = "FF11";
break;
}
}
// binarydata の文字列を 16 進数に変換
byte[] bytes = new byte[ binarydata.length() / 2 ];
for( int l = 0; l < bytes.length; l++ ){
// バイト値 一旦保存用
byte bycp = (byte)Integer.parseInt( binarydata.substring( l * 2, ( l + 1 ) * 2 ), 16 );
bytes[ l ] = (byte)( ~bycp + 1 );
}
// 全てのバイトを charbyte に追加
for( int l = 0; l < bytes.length; l++ ){ charbyte.add( bytes[ l ] );
System.out.println( "b" + bytes[ l ] );
}
}
// バイト配列から char を取得します。
// 引数から生成できない場合例外
private char setChar( byte[] b )
{
String bdata = DatatypeConverter.printHexBinary( b );
System.out.println( bdata );
if( code == CharCode.UTF_8 ){
switch( bdata ){
case "EFBC90": return '0';
case "EFBC91": return '1';
}
throw new IllegalArgumentException();
}
}
上のソースのコンストラクタでバイトを指定して、バイトに{ 0xEF, 0xBC, 0x92 }のデータ、UTF-8というデータを与えました。そしたら、
1 を入力した、というデータは取得できたのですが、コンストラクタで呼び出しているsetByte
で正しいバイトが入っていないようでした。
その当時は-の値だったので、ネットで調べ、整数値を出すことに成功しました。
しかし、現在出力されている値は 1 つめが 17 です。ただ、0xEFは 10 進数に直すと 239 なので、正しい値が入っていないようです。
// binarydata の文字列を 16 進数に変換のところでエラーが起きていると思われるのですが... どうしたらいいでしょうか。
package org.jyl.base.io;
/**
* 文字コードを定義した列挙型です。
*
* @author とあるゆっくり
*/
public enum CharCode
{
/**
* {@code ASCII} を示します。
* 最大バイト数は 1 バイトです。
*/
ASCII,
/**
* {@code EUC-jp} を示します。
* 半角カタカナの対応予定は現在ありません。
* 最大バイト数は制御文字も合わせ 3 バイトです。
*/
EUC,
/**
* {@code Shift-JIS} を示します。
* 最大バイト数は 2 バイトです。
*/
Shift_JIS,
/**
* {@code Unicode}( UTF-16 ) を示します。
* {@code UTF-8} は {@code UTF_8} を参照してください。
* 最大バイト数は 4 バイトです。
*/
Unicode,
/**
* {@code UTF-8} を示します。
* 技術的制限により、_を使用しています。
* 最大バイト数は 6 バイトです。
*/
UTF_8,
};
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
0xEF は int として見ると 239 かもしれませんが, (signed) byte としてみると -16 です.
(byte)( ~bycp + 1 );
の結果は 17 ですので, 「現在出力されている値は 1 つめが 17 」というのはコードの動きとしては合っていると思います.
この変換を外しては如何でしょうか.
つまり「その当時は-の値だった」のが正しく, 「整数値を出すことに成功」したのは byte が signed(値範囲:-128~127) ではなく unsigned (値範囲:0~255) と思われていた勘違いからのコードの破壊だったと思います.
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.37%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2019/01/22 19:13