はじめに
- 「~」などの文字が SJIS と UTF-8 で変換すると文字化けをします。
- 調べると【なんとなく】わかるのですが、しばらくすると、いつもわからなくなりこんがらがるので、まとめておきます。
文字化けする
文字化けする理由はいくつかあります。その中でも、SJIS と UTF-8 の変換によってで文字化けすることがあります。
これは、SJIS の 文字コード には「Shift_JIS」や「MS932」「Windows-31J」などあります。
この変換によって、文字化けします。
これ → 「~」 "から" ですね。
この文字が化けることがあります。(ほかにもありますが判りにくいので、一旦この文字で検証!)
まず、この文字のコードを「Shift_JIS」「Windows-31J (MS932)」で確認しましょう。
文字 | コード |
---|---|
~ | 0x8160 |
※「Windows-31J」と「MS932」は名前が違うが同じもの
この文字を「Shift_JIS」「Windows-31J」のそれぞれで「UTF-8」に変換しましょう。
Java でコードを書いて検証しましょう。
public static void readWrite(String inputFile, String inputCharsetName, String outputFile, String outputCharsetName) {
FileInputStream fileInputStream = null;
InputStreamReader inputStreamReader = null;
FileOutputStream fileOutputStream = null;
OutputStreamWriter outputStreamWriter = null;
System.out.println("-----------");
System.out.println("inputFile:" + inputFile);
System.out.println("inputCharsetName:" + inputCharsetName);
System.out.println("outputFile:" + outputFile);
System.out.println("outputCharsetName:" + outputCharsetName);
System.out.println("");
try {
fileInputStream = new FileInputStream(inputFile);
fileOutputStream = new FileOutputStream(outputFile);
inputStreamReader = new InputStreamReader(fileInputStream, inputCharsetName);
outputStreamWriter = new OutputStreamWriter(fileOutputStream, outputCharsetName);
int ch;
while ((ch = inputStreamReader.read()) != -1) {
System.out.print(Integer.toHexString(ch) + " ");
outputStreamWriter.write(ch);
}
} catch (IOException e) {
System.out.println(e);
} finally {
if (outputStreamWriter != null) {
try {
outputStreamWriter.close();
} catch (IOException e) {}
}
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {}
}
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {}
}
}
System.out.println("");
}
readWrite("./in/SJIS.txt", "Windows-31J", "./out/Windows-31J_to_UTF8.txt", "UTF-8");
readWrite("./in/SJIS.txt", "Shift_JIS", "./out/Shift_JIS_to_UTF8.txt", "UTF-8");
~
~
〜
-----------
inputFile:./in/SJIS.txt
inputCharsetName:Windows-31J
outputFile:./out/Windows-31J_to_UTF8.txt
outputCharsetName:UTF-8
ff5e
-----------
inputFile:./in/SJIS.txt
inputCharsetName:Shift_JIS
outputFile:./out/Shift_JIS_to_UTF8.txt
outputCharsetName:UTF-8
301c
なんと、元が「~」から「文字コード」によって UTF-8 上違う文字・コードになりました。
文字コード | コード |
---|---|
Shift_JIS | U+301C |
Windows-31J | U+FF5E |
UTF-8 から改めて、元の文字コードを利用して戻すと、「~」に戻りますが、
- Windows-31J で読み込み、UTF-8 に変換、Shift_JIS で出力
- Shift_JIS で読み込み、UTF-8 に変換、Windows-31J で出力
のように異なる文字コードにすると、文字化けします。
SJIS上の文字 | 読むときの文字コード | → | UTFの文字 | → | 書き込むときの文字コード | できたSJIS上の文字 |
---|---|---|---|---|---|---|
~ (0x8160) | Windows-31J | → | ~ (U+FF5E) | → | Windows-31J | ~ (0x8160) |
~ (0x8160) | Shift_JIS | → | 〜 (U+301C) | → | Shift-JIS | ~ (0x8160) |
~ (0x8160) | Windows-31J | → | ~ (U+FF5E) | → | Shift-JIS | 文字化け |
~ (0x8160) | Shift_JIS | → | 〜 (U+301C) | → | Windows-31J | 文字化け |
さて、読むときと書くときで、違う文字コードになることはあるのでしょうか。
それは、「クライアントが Windows、サーバが Unix系 でデータをやり取りする場合」です。
以下のような対処が必要になってきます。
クライアント Windows から サーバ Unix系 へデータを送信する場合
・Windows-31J で読み込み、UTF-8 に変換。
・「~ (U+FF5E)」を「〜 (U+301C)」に変換。
・サーバ側 Unix系にデータを送信。
サーバ Unix系 から クライアント Windows へデータを受信する場合
・サーバ側 Unix系からデータを受信。
・「〜 (U+301C)」を「~ (U+FF5E)」に変換。
・Windows-31J で書き込む。
SJIS上の文字 | 読むときの文字コード | UTFの文字 | 書き込むときの文字コード |
---|---|---|---|
~ (0x8160) | Windows-31J | ~ (U+FF5E) | Windows-31J |
~ (0x8160) | Shift_JIS | 〜 (U+301C) | Shift-JIS |
~ (0x8160) | Windows-31J | ~ (U+FF5E)から「〜 (U+301C)」に変換 | Shift-JIS |
~ (0x8160) | Shift_JIS | 〜 (U+301C)から「~ (U+FF5E)」に変換 | Windows-31J |
このような対処が必要になる文字として、以下の文字があります。
UTF-8 上で、文字の変換が必要になります。
SJIS | Windows-31J で読み込んでUTF-8へ変換 | Shift-JIS で読み込んでUTF-8へ変換 |
---|---|---|
~ (0x8160) | ~ (U+FF5E) | 〜 (U+301C) |
∥ (0x8161) | ∥ (U+2225) | ‖ (U+2016) |
- (0x817C) | - (U+FF0D) | − (U+2212) |
¢ (0x8191) | ¢ (U+FFE0) | ¢ (U+00A2) |
£ (0x8192) | £ (U+FFE1) | £ (U+00A3) |
¬ (0x81CA) | ¬ (U+FFE2) | ¬ (U+00AC) |
― (0x81CA) | ― (U+2015) | — (U+2014) |
では、その変換を入れたコードにしてみましょう。
readWriteForWindows31JtoShiftJIS("./in/SJIS.txt", "Windows-31J", "./out/Windows-31J_to_Shift_JIS.txt", "Shift_JIS");
readWriteForShiftJIStoWindows31J("./in/SJIS.txt", "Shift_JIS", "./out/Shift_JIS_to_Windows-31J.txt", "Windows-31J");
~∥-¢£¬―
public static void readWriteForWindows31JtoShiftJIS(String inputFile, String inputCharsetName, String outputFile, String outputCharsetName) {
FileInputStream fileInputStream = null;
InputStreamReader inputStreamReader = null;
FileOutputStream fileOutputStream = null;
OutputStreamWriter outputStreamWriter = null;
System.out.println("-----------");
System.out.println("inputFile:" + inputFile);
System.out.println("inputCharsetName:" + inputCharsetName);
System.out.println("outputFile:" + outputFile);
System.out.println("outputCharsetName:" + outputCharsetName);
System.out.println("");
try {
fileInputStream = new FileInputStream(inputFile);
fileOutputStream = new FileOutputStream(outputFile);
inputStreamReader = new InputStreamReader(fileInputStream, inputCharsetName);
outputStreamWriter = new OutputStreamWriter(fileOutputStream, outputCharsetName);
int ch;
while ((ch = inputStreamReader.read()) != -1) {
System.out.print(Integer.toHexString(ch) + " ");
switch (ch) {
case 0xff5e:
ch = 0x301c;
break;
case 0x2225:
ch = 0x2016;
break;
case 0xff0D:
ch = 0x2212;
break;
case 0xFFE0:
ch = 0x00A2;
break;
case 0xFFE1:
ch = 0x00A3;
break;
case 0xFFE2:
ch = 0x00AC;
break;
case 0x2015:
ch = 0x2014;
break;
}
outputStreamWriter.write(ch);
}
} catch (IOException e) {
System.out.println(e);
} finally {
if (outputStreamWriter != null) {
try {
outputStreamWriter.close();
} catch (IOException e) {}
}
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {}
}
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {}
}
}
System.out.println("");
}
public static void readWriteForShiftJIStoWindows31J(String inputFile, String inputCharsetName, String outputFile, String outputCharsetName) {
FileInputStream fileInputStream = null;
InputStreamReader inputStreamReader = null;
FileOutputStream fileOutputStream = null;
OutputStreamWriter outputStreamWriter = null;
System.out.println("-----------");
System.out.println("inputFile:" + inputFile);
System.out.println("inputCharsetName:" + inputCharsetName);
System.out.println("outputFile:" + outputFile);
System.out.println("outputCharsetName:" + outputCharsetName);
System.out.println("");
try {
fileInputStream = new FileInputStream(inputFile);
fileOutputStream = new FileOutputStream(outputFile);
inputStreamReader = new InputStreamReader(fileInputStream, inputCharsetName);
outputStreamWriter = new OutputStreamWriter(fileOutputStream, outputCharsetName);
int ch;
while ((ch = inputStreamReader.read()) != -1) {
System.out.print(Integer.toHexString(ch) + " ");
switch (ch) {
case 0x301c:
ch = 0xff5e;
break;
case 0x2016:
ch = 0x2225;
break;
case 0x2212:
ch = 0xff0D;
break;
case 0x00A2:
ch = 0xFFE0;
break;
case 0x00A3:
ch = 0xFFE1;
break;
case 0x00AC:
ch = 0xFFE2;
break;
case 0x2014:
ch = 0x2015;
}
outputStreamWriter.write(ch);
}
} catch (IOException e) {
System.out.println(e);
} finally {
if (outputStreamWriter != null) {
try {
outputStreamWriter.close();
} catch (IOException e) {}
}
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {}
}
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {}
}
}
System.out.println("");
}
ご了承ください
- 自分が何とか学習した内容を記載しており、間違ってはいないと思いますが、そのあたりは生暖かくご覧いただければ、嬉しいです。
参考にさせていただいたページ
参考にさせていただきました、ありがとうございます。
- UTF-8 → cp932(Shift_JIS)変換表
- とほほのJava入門 - 入出力