SJIS-macに変換したはずなのにSJIS-winになる

# SJIS-macに変換したはずなのにSJIS-winになる

StackOverflowに[mb_detect_encoding does not detect SJIS-mac?](https://stackoverflow.com/questions/57984049/mb-detect-encoding-does-not-detect-sjis-mac/63772728)という投稿がありました。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/9b35590b-72a4-975f-769e-08ac642d00cd.png)

ということらしいので、[UTF-8からSJIS-macに変換](https://3v4l.org/Dm4sA)してみましょう。

```php
$utf8Str = "❶❷❸❹❺";

$sjisStr = mb_convert_encoding($utf8Str, 'SJIS-mac');

echo(mb_detect_encoding($sjisStr, ['UTF-8','SJIS-mac', 'SJIS-win', 'SJIS'])); // SJIS-win ←
```

`SJIS-mac`に変換したはずなのに、何故か`SJIS-win`と判定されてしまいます。

そもそも`SJIS-mac`ってなんだよって話ですが、単に[MacJapanese](https://ja.wikipedia.org/wiki/MacJapanese)のエイリアスです。
従って`MacJapanese`と書いても同じく、正しく誤判定されます。

そして[コメント欄](https://stackoverflow.com/questions/57984049/mb-detect-encoding-does-not-detect-sjis-mac/63772728#63772728)に`This is a bug in PHP's mbstring extension`『mbstringエクステンションのバグじゃよ』という人が現れています。
間違ったコードを書いたときに自分のせいではなく言語・ライブラリのせいにする人はよくいますが、[この人](https://stackoverflow.com/users/960828/alex-d)の場合は適当言ってるわけではなく本当にバグです。

# https://github.com/php/php-src/pull/6052

コメント主の[alexdowad](https://github.com/alexdowad)は先日、PHPソースに[プルリク](https://github.com/php/php-src/pull/6052)を送り付けました。
中身はmbstringエクステンションに関するもので、バグ修正、不要なコードの削除、トリッキーなコードのリファクタリング、高速化、テストカバレッジ上昇など多くの改善が含まれています。

これがなかなか大規模で、91コミット5万行以上のごつい変更となっています。
さすがに大半は[テスト用の変換テーブル](https://github.com/php/php-src/tree/231c5ec05fd338868968b87f826b9f610184d264/ext/mbstring/docs)みたいですが、それでも実コードの修正も数千行は入っています。

mbstringなので日本語に影響するかもしれないということで少し覗いてみました。

## https://github.com/php/php-src/pull/6052#issue-475811327

このプルリクはmbstringの改善を目的としていいる。

・不要なコードを削除。
・曖昧なコードを読みやすくする。
・残ってしまったトリッキーなコードにはコメントを追加する。
・全てを高速化する。
・バグの修正。
・テストカバレッジの向上。
・一貫性を向上させるため、セマンティクスを調整した。

もしかしたらパフォーマンスのためにあえてそのように書かれているのではないかと考えていた部分もあったが、実際はそうでもなかった。
リファクタリングすることは、パフォーマンスのためにも良いことだった。
性能チェックのために591のベンチマークを走らせた。
幾つか性能劣化が見つかったが、それも修正した。
最適化の余地はまだまだ大量に残されているので、いずれそれらも改善する予定である。


## https://github.com/php/php-src/pull/6052/commits/0880fc00094f363dcaac6762f2ec94a02e380baf

mb_check_encodingを最適化したよ
これによって[mb_check_encoding](https://www.php.net/manual/ja/function.mb-check-encoding)が50%高速化されます。

## https://github.com/php/php-src/pull/6052/commits/6197b8e7a2ec81e63e1079812741dccdab0b6417

HTMLの数値エンティティ変換を最適化したよ。
これによって[mb_encode_numericentity](https://www.php.net/manual/ja/function.mb-encode-numericentity.php)が10%高速化されます。

## https://github.com/php/php-src/pull/6052/commits/e3d5a05a97c5ef8d60489ca3491930bf75d79647

mb_str_splitの本体をmbfl_str_splitに移したよ。あとバグも修正した。


## https://github.com/php/php-src/pull/6052/commits/4d9999674ec9fc298e3fe26e7445f24c50575792

ISO-8859-xエンコーディングの変換テーブルとテストスイートを追加したよ。

ちなみに[ISO-8859-3(Latin-3)](https://github.com/php/php-src/pull/6052/commits/b9b169ee3cecf6b0c0c5be3e6cd65cd09817ac94)、[ISO-8859-6 (Latin/Arabic)](https://github.com/php/php-src/pull/6052/commits/b0adb720051b15dee0d812bf9bcf6d7d4f1d9449)、[ISO-8859-7 (Latin/Greek)](https://github.com/php/php-src/pull/6052/commits/8c263adfb28d9c90e3c7203719638b863de90d56)、[ISO-8859-8 (Latin/Hebrew)](https://github.com/php/php-src/pull/6052/commits/4caa950cbf264b939adb62edcc3d3ff5b4565df4)、[ISO-8859-16 (Latin-10)](https://github.com/php/php-src/pull/6052/commits/339cf59beb453a374509ed8a27a2656f0a985ae5)が追加されてる。


## https://github.com/php/php-src/pull/6052/commits/322bf79b92ab98d54fde1b30c9ebb633b71d8391

`MBFL_CHP_{CTL,DIGIT,UALPHA,LALPHA,MSPECIAL}`使ってないから削除したよ。

## https://github.com/php/php-src/pull/6052/commits/5b0984a5a513cdc7b7a76986c7dc391c90725d3f

意味のないポインタ参照を削除したよ。

```c
	(const char *(*)[])&mbfl_language_uni_aliases,
```

というか何これ。

## https://github.com/php/php-src/pull/6052/commits/136a03103e8566fa89189c8dc65cb6bffe5c92a4

[IMAP](https://tools.ietf.org/html/rfc3501)のために、UTF-7の改良版[Modified UTF-7](https://smdn.jp/programming/netfx/tips/modified_utf7/)を追加したよ。

## https://github.com/php/php-src/pull/6052/commits/fb98c004cb71fe0707ce35bc46c9cfb8465b9891

Shift-JIS-2004を追加したよ。

## https://github.com/php/php-src/pull/6052/commits/2621a78593d8bc1ef5131521b56ca1d98a86776e

ISO-2022-JP-2004の識別を厳密にしたよ。

## https://github.com/php/php-src/pull/6052/commits/26204445a7e8b08ee5a0dbbbe247e970e75df8dc

[mb_convert_kana](https://www.php.net/manual/ja/function.mb-convert-kana.php)が存在しない変換オプションに例外を出すようにしたよ。


## https://github.com/php/php-src/pull/6052

動作検証のためにテストコードを追加したら、既存コードに多くのバグを発見してしまったよ。

## https://github.com/php/php-src/pull/6052#issuecomment-695835716

mb_strposに面白い問題を発見したよ。
[mb_strpos](https://www.php.net/manual/ja/function.mb-strpos)には`$needleの長さ > $haystackの長さ`だったら即falseにするって処理が入ってるんだけど、同じ文字を複数の形式で表すことができるエンコーディングもあって、その場合`$needleの長さ > $haystackの長さ`になることがあるんだよね。


他にも大量のコミットが存在します。

# Nikita

レビュアーとして[Nikitaが現れる](https://github.com/php/php-src/pull/6052#pullrequestreview-478644195)。
いや本当、何処に行ってもこの人がいるな。

mbstringは元々[libmbfl](https://github.com/moriyoshi/libmbfl)というライブラリを使ってたんだけど、これはもう長いことメンテされていない。
なのでPHP7.3/7.4でこのあたりに大幅なメスを入れたんだけど、まだ概念的には別のライブラリとして扱っている。
このプルリクではlibmbflを捨て、直接Zend APIとして使用するようにしてるけど、それによるデメリットはないので今後はそうする方向がいいと思う。

あとヘッダ部分の書式、何処から来てるのかはわからないけど3スペースのインデントが使われているけど、これはそのままのほうがいいだろう。

ものすごい勢いで突っ込み・コミットを入れているものの、全体的には反対ではなさそうです。
おそらくこの変更はそのうちマージされそうな雰囲気です。


# 感想

いやあ、この人やばいね。
日本人でも全然わかってない人も多い(私とか)Shift_JIS-2004やらISO-2022-JP-2004やらも的確に対応して大量のテストを追加してさらに最適化・高速化まで成し遂げてしまう。
すごすぎる熱量と能力です。

さらにこのプルリク、`(part 1)`とか書いてありますからね。
パート2では今回あまり手の入っていない`mb_convert_encoding`あたりにも最適化が入りそうですね。

しかし、mbstringの主戦場である日本や中国からのコントリビュートが全くないのが気になります。
極端な話英語圏ではmbstringがなくてもなんとかなりますから、切り捨てられないためにも日本からも有識者が参加して存在感を出してもらいたいところですね。