【Android→WEB】円マーク・バックスラッシュのコードポイント変換（コードポイント：A5 or C2A5 ⇔ C5）

# 概要
"円マーク（半角￥）"をAndroidで用いていた際に、
Windowsで"バックスラッシュ（半角／）"として、文字コードが扱われてしまった為、
円マークとバックスラッシュとの文字コードポイントの違いと、本対策について纏めました。

※ソースコードは、全てJavaを用いております。

# 各環境でのコードポイントの違い（円コード・バックスラッシュ）
各環境でのUTF-8で、
円コードとバックスラッシュは、以下のコードポイントが使用されます。
> Windows Web
円マーク: 5C
バックスラッシュ: 5C  

> Mac・iOS・Android Web
円マーク: A5
バックスラッシュ: 5C

> iOS・Androidネイティブアプリ
円マーク: C2A5
バックスラッシュ: 5C

[参考URL]
[円マークとバックスラッシュの文字コード](https://qiita.com/alt_yamamoto/items/578cb9da6a2225030632)

# 対策
対策としては、円マークのコードポイントを全て、
Windows Web（コードポイント：A5 or C2A5 ⇒ C5）に寄せる対策としました。

- A5 ⇒ C5
- C2A5 ⇒ C5

# ソースコード作成
コードポイント変換を実施するクラス（CodePointConversion.java）を作成しました。
対象のコードポイント（A5 or C2A5）を、コードポイント（C5）に変換を行います。

```java:CodePointConversion.java
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();
    }
}
```

# テストコード作成
動作確認用のテストコードです。
入力値と出力値に関しては、実行結果をご確認ください。

```java:CodePointConversionTest.java
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でのコードポイント変換を行う際に、ご活用ください。