概要
"円マーク(半角¥)"をAndroidで用いていた際に、
Windowsで"バックスラッシュ(半角/)"として、文字コードが扱われてしまった為、
円マークとバックスラッシュとの文字コードポイントの違いと、本対策について纏めました。
※ソースコードは、全てJavaを用いております。
各環境でのコードポイントの違い(円コード・バックスラッシュ)
各環境でのUTF-8で、
円コードとバックスラッシュは、以下のコードポイントが使用されます。
Windows Web
円マーク: 5C
バックスラッシュ: 5C
Mac・iOS・Android Web
円マーク: A5
バックスラッシュ: 5C
iOS・Androidネイティブアプリ
円マーク: C2A5
バックスラッシュ: 5C
[参考URL]
円マークとバックスラッシュの文字コード
対策
対策としては、円マークのコードポイントを全て、
Windows Web(コードポイント:A5 or C2A5 ⇒ C5)に寄せる対策としました。
- A5 ⇒ C5
- C2A5 ⇒ C5
ソースコード作成
コードポイント変換を実施するクラス(CodePointConversion.java)を作成しました。
対象のコードポイント(A5 or C2A5)を、コードポイント(C5)に変換を行います。
import java.util.Map;
import java.util.HashMap;
import java.lang.StringBuilder;
/**
* コードポイント変換クラス
* @author HogeHoge
*/
public class CodePointConversion {
// コードポイント変換テーブル。KEY→VALUEのコードポイントに変換する。
private static Map<Integer, Integer> conversion_map = new HashMap<Integer, Integer>() {
// ¥ → \
{put(0xA5, 0x5C);
put(0xC2A5, 0x5C);}
};
/**
* コードポイント変換を行う
* @param str コードポイント変換を行う文字列
* @return コードポイント変換後の文字列
*/
public static String convertCordPoint(String str) {
// nullチェック
if (str == null) {
return str;
}
StringBuilder sb = new StringBuilder(str);
// 取得文字分ループ
for(int i = 0; i < sb.length(); i++) {
// 取得文字のコードポイントを取得
int code_point = sb.codePointAt(i);
for (Map.Entry<Integer, Integer> entry : conversion_map.entrySet()) {
if (code_point == entry.getKey()) {
// コードポイント変換対象の場合、コードポイント変換を実施する。
String converted_char = new String(Character.toChars(entry.getValue()));
sb.replace(i, i+1, converted_char);
}
}
}
return sb.toString();
}
}
テストコード作成
動作確認用のテストコードです。
入力値と出力値に関しては、実行結果をご確認ください。
import org.junit.jupiter.api.Test;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
class CodePointConversionTest {
@Test
void testConvertCordPoint001() {
// 【入力値】¥¥ ※¥は半角文字。
String input_str = new String(Character.toChars(0xA5)) + new String(Character.toChars(0xC2A5));
// 【期待値】\\ ※最初の\はエスケープ文字。
String expect_str = "\\\\";
System.out.println("【入力値】\n" + input_str);
System.out.println("【入力コードポイント】\n" + Integer.toHexString(input_str.codePointAt(0)) + "\n" + Integer.toHexString(input_str.codePointAt(1)));
// コードポイント変換。¥→\に変換される。
String result_str = CodePointConversion.convertCordPoint(input_str);
// 出力値
System.out.println("\n【出力値】\n" + result_str);
System.out.println("【出力コードポイント】\n" + Integer.toHexString(result_str.codePointAt(0)) + "\n" + Integer.toHexString(result_str.codePointAt(1)));
// 出力の結果確認。
assertThat(result_str, is(expect_str));
}
}
以下実行結果。
【入力値】
\?
【入力コードポイント】
a5
c2a5
【出力値】
\\
【出力コードポイント】
5c
5c
上記の入力値は"?"となっておりますが、Windows端末の画面の表示上の問題です。
実際には「円マーク: A5 円マーク: C2A5」の文字列が、入力値として入っております。
バックスラッシュをAndroid上で円コードとして扱う方法
今まで記載した方法は、円マークをバックスラッシュ(コードポイント:A5 or C2A5 ⇒ C5)に、
コードポイント変換する方法を記載しましたが、
Android上では、バックスラッシュ⇒円マーク(コードポイント:C5 ⇒ A5)として扱いたいケースがあると思います。
その際には、conversion_map(コードポイント変換テーブル)のKEY, VALUEを逆にする形で扱って下さい。
(例)C5のコードポイントを、A5として扱う方法。
// コードポイント変換テーブル。KEY→VALUEのコードポイントに変換する。
private static Map<Integer, Integer> conversion_map = new HashMap<Integer, Integer>() {
// \ → ¥
{put(0x5C, 0xA5);}
};
※C5のコードポイントを、A5かC2A5として扱うかは、各環境によって変更する事。
終わりに
今回は、円マーク・バックスラッシュのコードポイント変換(コードポイント:A5 or C2A5 ⇔ C5)を行う方法を記載しましたが、
conversion_map(コードポイント変換テーブル)に、コードポイントを追加するだけで、
様々なコードポイントを変換出来るようにしてあります。
もし宜しければJavaでのコードポイント変換を行う際に、ご活用ください。