Apex で文字コード変換できるユーティリティクラスを作った

# はじめに
最近のシステムはほとんどの場合 UTF-8 が標準の文字コードになっており、 Salesforce も例に漏れずあらゆるインタフェースで UTF-8 を採用しています。しかし、稀に Salesforce (Apex) から古いシステムを触る必要があるときや、後処理の都合などで文字列を Shift_JIS や EUC-JP などに変換する必要に迫られる場合があります。Java や Python などの主要なプログラミング言語では標準で文字コードの変換が可能ですが、Apex は文字列の文字コード変換用のメソッドは存在しておらず、少しテクニカルに処理する必要があります。

# 方針
`EncodingUtil.urlEncode` を使えばマルチバイト文字は主要な文字コードに変換することができます。
ただしこのメソッドだと ASCII 文字が変換されないので、 `EncodingUtil.urlEncode` に渡す前にASCII文字列だけを個別に16進数表記の文字列に変換します。すべての文字列を変換先の文字コードの16進数表記にしたら `EncodingUtil.convertFromHex` で Blob 形式に変換して処理完了となります。

# 作ったもの

https://gist.github.com/kaku10/8a89e99a00b4440e066095abae69e409

主要な日本語対応の下記文字コードをエンコードできるメソッドを用意しています。
- EUC-JP
- Shift_JIS
- ISO-2022-JP
- UTF-16(BE)
- UTF-16(LE)
- UTF-32(BE)
- UTF-32(LE)

# 使い方
```apex
// 文字コード変換
Blob eucJp = CharacterEncodingUtil.encodeToEucJp('文字列');
Blob shiftJis = CharacterEncodingUtil.encodeToShiftJis('文字列');
Blob iso2022Jp = CharacterEncodingUtil.encodeToIso2022Jp('文字列');
Blob utf16 = CharacterEncodingUtil.encodeToUtf16('文字列');
Blob utf16le = CharacterEncodingUtil.encodeToUtf16LE('文字列');
Blob utf32 = CharacterEncodingUtil.encodeToUtf32('文字列');
Blob utf32le = CharacterEncodingUtil.encodeToUtf32LE('文字列');
```

```apex
// 改行コードを指定して文字コード変換
Blob eucJp = CharacterEncodingUtil.encodeToEucJp('文字列', CharacterEncodingUtil.NewlineSeparator.CRLF);
Blob shiftJis = CharacterEncodingUtil.encodeToShiftJis('文字列', CharacterEncodingUtil.NewlineSeparator.LF);
Blob iso2022Jp = CharacterEncodingUtil.encodeToIso2022Jp('文字列', CharacterEncodingUtil.NewlineSeparator.CR);
Blob utf16 = CharacterEncodingUtil.encodeToUtf16('文字列', CharacterEncodingUtil.NewlineSeparator.CRLF);
Blob utf16le = CharacterEncodingUtil.encodeToUtf16LE('文字列', CharacterEncodingUtil.NewlineSeparator.LF);
Blob utf32 = CharacterEncodingUtil.encodeToUtf32('文字列', CharacterEncodingUtil.NewlineSeparator.CR);
Blob utf32le = CharacterEncodingUtil.encodeToUtf32LE('文字列', CharacterEncodingUtil.NewlineSeparator.CRLF);
```

```apex
// 変換時のデフォルトの改行コードの変更
CharacterEncodingUtil.defaultNewLineSeparator = CharacterEncodingUtil.NewlineSeparator.LF;
// 改行コード LF で EUC-JP にエンコード
Blob eucJp = CharacterEncodingUtil.encodeToEucJp('文字列');
```

# 実装例
Apex で Shift_JIS 形式の CSV をファイルとして保存する処理の実装例
```apex
String DIGIT = '0123456789';
String ALPHABET = 'loremipsum';
String HIRAGANA = 'いろはにほへと';
String KATAKANA = 'イロハニホヘト';
String HALF_KATAKANA = 'ｲﾛﾊﾟﾆﾎﾞﾍﾟﾄ';
String KANJI = '高崎髙﨑';
String SPACE = ' 　\t';
String SYMBOL = '!"#$%&()[]{}`~=-\\';
String EMOJI = '😇🏴󠁧󠁢󠁷󠁬󠁳󠁿👶🏿';

String csvHeader = String.join(new List<String>{
        'DIGIT',
        'ALPHABET',
        'HIRAGANA',
        'KATAKANA',
        'HALF_KATAKANA',
        'KANJI',
        'SPACE',
        'SYMBOL',
        'EMOJI'
}, ',');
String csvBody = String.join(new List<String>{
        DIGIT,
        ALPHABET,
        HIRAGANA,
        KATAKANA,
        HALF_KATAKANA,
        KANJI,
        SPACE,
        SYMBOL,
        EMOJI
}, ',');
ContentVersion cv = new ContentVersion();
cv.ContentLocation = 'S';
cv.PathOnClient = 'example.csv';
cv.Title = 'example.csv';
cv.VersionData = CharacterEncodingUtil.encodeToShiftJis(csvHeader + '\n' + csvBody);
insert cv;
```


# 制限/留意事項
- 変換先の文字コード上に存在しない文字（特に絵文字や機種依存文字など）は ? に変換されます
- 大量の文字列を変換する場合、CPU時間に注意してください
    - 手元の環境だとShift_JIS変換のマルチバイト文字のみで 10,000 文字あたり 200 ~ 250 ms、ASCII文字のみで 10,000 文字あたり 平均 500 ~ 600 msほど消費します
        - UTF-16, UTF-32 はさらにASCII文字の処理負荷が1.5 ~ 2倍ほど
        - もう少し工夫すればチューニングできる...?