Javaで文字コードの変換を行う

相変わらずJavaの面倒さは異常。

ソースコード

import java.io.*;
import java.nio.*;
import java.nio.charset.*;
import java.util.*;

/**
 * 文字コードの変換を行う。
 */
public class wavedash {

    /**
     * Windows-31Jのファイルを読み込んでISO-2022-JPのバイト配列に変換する。
     * その後、ISO-2022-JPのバイト配列をUnicodeに変換してWindows-31Jのファイルに出力する。
     * 
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        String unicode = readWindows31j();
        readIso2022jp();

        byte[] jis = unicode2iso2022jp(unicode);
        unicode = iso2022jp2unicode(jis);

        writeWindows31j(unicode);
    }

    /**
     * Unicodeの文字列をISO-2022-JPのバイト配列に変換する。
     * 
     * Windows-31JからUnicodeに変換した場合とISO-2022-JPからUnicodeに変換した場合で
     * 異なるコードポイントになる文字は事前に置換を行う。
     * 置換を行わない場合はUnmappableCharacterExceptionが発生する。
     * 
     * CharsetEncoder.encode(CharBuffer).array()はCapacityの分だけバイト配列を返す。
     * このバイト配列には余分なものが含まれているので必要な分だけを取り出す。
     * 
     * @param unicode Unicodeの文字列
     * @return ISO-2022-JPのバイト配列
     */
    private static byte[] unicode2iso2022jp(String unicode) {
        CharsetEncoder jisEncoder = Charset.forName("ISO-2022-JP").newEncoder();
        ByteBuffer encoded = null;
        byte[] capacity = null;
        List<Byte> temp = new ArrayList<Byte>();
        byte[] result = null;

        //(Windows-31J -> Unicode) -> (ISO-2022-JP -> Unicode)
        unicode = unicode.replaceAll("\uff5e", "\u301c"); //~
        unicode = unicode.replaceAll("\uff0d", "\u2212"); //-

        try {
            encoded = jisEncoder.encode(CharBuffer.wrap(unicode.toCharArray()));
            capacity = encoded.array();
        } catch (CharacterCodingException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < encoded.limit(); i++) {
            temp.add(capacity[i]);
        }

        result = new byte[temp.size()];
        
        for (int i = 0; i < result.length; i++) {
            result[i] = temp.get(i);
        }

        return result;
    }

    /**
     * ISO-2022-JPのバイト配列をUnicodeの文字列に変換する。
     * 
     * Windows-31JからUnicodeに変換した場合とISO-2022-JPからUnicodeに変換した場合で
     * 異なるコードポイントになる文字は置換を行う。
     * 
     * @param jis ISO-2022-JPのバイト配列
     * @return Unicodeの文字列
     */
    private static String iso2022jp2unicode(byte[] jis) {
        CharsetDecoder jisDecoder = Charset.forName("ISO-2022-JP").newDecoder();
        CharBuffer unicode = null;
        
        try {
            unicode = jisDecoder.decode(ByteBuffer.wrap(jis));
        } catch (CharacterCodingException e) {
            e.printStackTrace();
        }

        //(ISO-2022-JP -> Unicode) -> (Windows-31J -> Unicode)
        HashMap<String, String> converter = new HashMap<String, String>();
        converter.put("\u301c", "\uff5e"); //~
        converter.put("\u2212", "\uff0d"); //-

        Iterator<String> conveterKeySetIterator = converter.keySet().iterator();

        while (conveterKeySetIterator.hasNext()) {
            char replaceTarget = conveterKeySetIterator.next().charAt(0);

            for (int i = 0; i < unicode.limit(); i++) {
                if (unicode.get(i) == replaceTarget) {
                    unicode.put(i, converter.get(String.valueOf(replaceTarget)).charAt(0));
                }
            }            
        }

        return unicode.toString();
    }

    /**
     * Windows-31Jのファイルを読み込む。
     * 
     * @return 文字列
     */
    private static String readWindows31j() {
        BufferedReader reader = null;
        String windows31j = null;

        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\var\\temp\\windows31j.txt"), "Windows-31J"));
            windows31j = reader.readLine();
            
            //Windows-31JをUnicodeに変換したコードポイントの確認
            System.out.println("read windows31j=" + dump(windows31j));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            closeReader(reader);
        }
        
        return windows31j;
    }

    /**
     * ISO-2022-JPのファイルを読み込む。
     * 
     * @return 文字列
     */
    private static String readIso2022jp() {
        BufferedReader reader = null;
        String iso2022jp = null;

        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\var\\temp\\iso2022jp.txt"), "ISO-2022-JP"));
            iso2022jp = reader.readLine();

            //ISO-2022-JPをUnicodeに変換したコードポイントの確認
            System.out.println("read iso2022jp=" + dump(iso2022jp));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            closeReader(reader);
        }
        
        return iso2022jp;        
    }
    
    /**
     * Windows-31Jのファイルに書き込む。
     * 
     * @param unicode 文字列
     */
    private static void writeWindows31j(String unicode) {
        BufferedWriter writer = null;

        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\var\\temp\\windows31j_out.txt"), "Windows-31J"));
            writer.write(unicode);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            closeWriter(writer);
        }
    }

    /**
     * Unicodeの文字列を16進数で表現する。
     * 
     * @param value 文字列
     * @return 文字列の16進数の表現
     */
    private static String dump(String value) {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < value.length(); i++) {
            sb.append(Integer.toHexString(value.codePointAt(i)));
            sb.append(" ");
        }

        return sb.substring(0, sb.length() - 1);
    }

    /**
     * バイト配列を16進数で表現する。
     * 
     * @param value バイト配列
     * @return バイト配列の16進数の表現
     */
    private static String dump(byte[] value) {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < value.length; i++) {
            sb.append(Integer.toHexString(value[i]));
            sb.append(" ");
        }
        
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * 文字ストリームを閉じる。
     * 
     * @param reader 文字ストリーム
     */
    private static void closeReader(Reader reader) {
        try {
            if (reader != null) {
                reader.close();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文字ストリームを閉じる。
     * 
     * @param writer 文字ストリーム
     */
    private static void closeWriter(Writer writer) {
        try {
            if (writer != null) {
                writer.close();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
    

関連情報

2007, AfternoonTea