この2つの違いはなんでしょうか
1.ポセイドン
2.ポセイドン
見た目は同じだけど…
経緯
スクレイピングで取得した文字列を画像に出力するシステムを作っている時のこと
なんか出力結果がおかしい
「ポセイドン」と綺麗に出力したいのに濁点と半濁点が分離した「ホ゜セイト゛ン」となってしまう。
もし読み込ませているデータ自体が「ホ゜セイト゛ン」ならわかるけど
読み込み先の文字列を見てみると「ポセイドン」…なぜだ
Unicodeによる結合
どうやら2文字のデータを1文字に纏める結合というものが行われていて、特に今回スクレイピングみたいにwebからごちゃごちゃ取ってきたりすると混同しがちらしい。
どういう理屈で混同してるのかとか、なぜこんなものが生まれてしまったのかはさておき、とりあえずこの「ポセイドン」を「ポセイドン」にしたい。
とりあえず文字コード見てみよう
<?php
$poseidon = "ポセイドン";
$moji_code = substr(json_encode($poseidon), 1, -1);
echo $moji_code;
\u30db\u309a\u30bb\u30a4\u30c8\u3099\u30f3
てことはつまり
\u30db\u309a => ホ + 半濁点
\u30c8\u3099 => ト + 濁点
ということで「\u309a」(半濁点)と「\u3099」(濁点)をこの状態で置換してjson_decode()すればよさそう。
かといって「ホ」(\u30db)を直で「ポ」(\30ddらしい)に直で変えるのはすごく面倒なので
mb_convert_kana()のKとVオプションを使って元に(?)戻す。
こいつを使えば、「ポセイドン」 => 「ポセイドン」に変換できる。つまり「゚」と「゙」に置換できればオーケー。
順序としては
①結合文字列を文字コードで出して
②「\u309a」(結合文字の半濁点)を「\u309c」に、「\u3099」(結合文字の濁点)を「\u309b」に置換
③デコードして
④全角カナを半角カナにして(ホ゜セイト゛ン => ポセイドン)
⑤濁点付き半角カナを全角カナに変換(ポセイドン => ポセイドン)
でいけそう
<?php
$poseidon = "ポセイドン";
//①
$moji_code = substr(json_encode($poseidon), 1, -1);
//②
$moji_code = str_replace("\u3099",'\u309b',$moji_code);
$moji_code = str_replace("\u309a",'\u309c',$moji_code);
//③
$decode_poseidon = json_decode(sprintf('"%s"', $moji_code));
//④
$decode_poseidon = mb_convert_kana($decode_poseidon,"aks","utf-8");
//⑤
$decode_poseidon = mb_convert_kana($decode_poseidon,"KV","utf-8");
echo $decode_poseidon;
気になる結果は…
ポセイドン
いやわからんわ。画像で出力して確認する
やったーーーーーー!!!
感想
こんな地味なのがqiita初投稿になるなんて
ちなみになぜポセイドンなのかというと、濁点と半濁点を含む1単語がこれ以外「パリピギャル」くらいしか思い浮かばなかったからです。
最後まで読んでいただきありがとうございました。
8/25 追記
コメントでNormalizerクラスを使うと1行で済むことをご教授頂きました。
誠にありがとうございます。無知を恥じるばかりです。