Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
文字とはなにか - PHPの文字コード処理について - PHP Lovers Meetup #5
Search
てきめん tekimen
PRO
March 23, 2024
1
230
文字とはなにか - PHPの文字コード処理について - PHP Lovers Meetup #5
Gina Peter Banyardさんをお迎えして急遽行われたMeetupで発表したスライドです。PHPカンファレンス北海道2024のをちょっと修正を加えたものです。
てきめん tekimen
PRO
March 23, 2024
Tweet
Share
More Decks by てきめん tekimen
See All by てきめん tekimen
PHP Internals わいわい #3 mb_*関数を作ってみよう
youkidearitai
PRO
0
39
Windows版php-srcデバッグ方法
youkidearitai
PRO
1
47
PHP Internals わいわい #1 の資料
youkidearitai
PRO
1
1.1k
mb_trim関数を作りました
youkidearitai
PRO
1
740
PHPの次期バージョンはこの時期どうなっているのか - Internalsの開発体制について - PHPカンファレンス小田原
youkidearitai
PRO
1
650
はじめてのOSSコントリビュート
youkidearitai
PRO
11
3.6k
文字とはなにか - PHPの文字コード処理について -
youkidearitai
PRO
0
710
現在のmbstringの立ち位置 これからどうなっていくのか
youkidearitai
PRO
0
240
PHP 8.3のmbstringの進化を見てください - コントリビューターとしてのかかわり -
youkidearitai
PRO
0
1.2k
Featured
See All Featured
Optimising Largest Contentful Paint
csswizardry
33
3k
We Have a Design System, Now What?
morganepeng
51
7.3k
Writing Fast Ruby
sferik
628
61k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
27
1.5k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
850
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
59k
Thoughts on Productivity
jonyablonski
68
4.4k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
171
50k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
3
220
4 Signs Your Business is Dying
shpigford
182
21k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
160
15k
Optimizing for Happiness
mojombo
376
70k
Transcript
文字とはなにか - PHPの文字コード処理について - Ginaさんようこそバージョン
自己紹介 てきめん (tekimen) Yuya Hamada(濱田 侑弥) • https://tekitoh-memdhoi.info • X(twitter):
@youkidearitai • https://github.com/youkidearitai • https://mstdn.jp/tekimen • https://phpc.social/youkidearitai • サイボウズ株式会社に所属してます オレ
まずはじめに mb_ucfirst関数とmb_lcfirst関数がマージされました!
コンピューターで文字を表すの基本 • コンピューターは数値しか扱えません • そこで、とある数値をAなどと紐づけていきました • それが文字コードです • 文字コードに照らし合わせて文字を表示してくれる のがフォントですね
Unicodeがよい • ざっくり言ってしまうとUnicodeはいいぞ • 文字化けから開放してくれたぞ!ってなる • 絵文字も使えるぞ 🎉🎉
Unicodeって何? • 世界中のすべての文字を収録しようというもの – ISO/IEC 10646 という工業規格があって、Unicodeと等 しくなるようになっています • JIS
X 0221が現在の日本の工業規格(JIS)での規格です – Unicodeのバージョンに伴って、収録されていく文字が 増えています
UnicodeとJIS X 0221との関係 Unicode ISO/IEC 10646 JIS X 0221 同期
日本版 ※各仕様書を読んだらこの図になりましたが「プログラマのための文字コード技術入 門」もほぼ同じ図になっていました
Unicodeのバージョンについて • 現在最新版は15.1です。 • 2024年ではUnicode 16.0に むけて作業が進められていま す – http://blog.unicode.org/
2023/11/utc-177-highlig hts.html – alphaがリリースされました
絵文字の存在 • バージョンなんてどうでも良くね?と思いがちです が、実はそうもいかないのです • みなさんはこんなことはありませんか? – 私の推しマークは です、時々違う方がいます。気をつ 🩵
けてくださいなどと呼びかけているアイドルさん – 🙇 と♂♀が分割してた
スマートフォンは絵文字を入力しやすい • スマートフォンならば簡単に絵文字を選んで入力す ることができます • 新しいスマートフォンほど新しい絵文字を入力しやす くなります • その一方で、大切に長くスマートフォンを使っている 人もいます
その結果起こること • Unicodeのバージョンに気を使う必要があります – 古いスマートフォンでは絵文字が見えなかったり、分か れて見えたりします – 新しいスマートフォンでは当たり前のように新しい Unicodeのバージョンの絵文字が使えます
🩵はどうでしょうか • https://emojipedia.org/ja/%E6%B0%B4%E8% 89%B2%E3%81%AE%E3%83%8F%E3%83%BC %E3%83%88 • どうやらUnicode 15.0で入ったようです – 2023年現在の最新バージョンは15.1です
– かなり新しい絵文字です – 古いスマートフォンでは見えないでしょうね…
🙇と♂♀が分割してた • このケースの場合、土下座をしている人と♂や♀の マークが分割して見えることがあります • 対応している機種であれば、「 」、「 」と表示され 🙇♂️ 🙇♀️
ます • いきなりですがPHPでmb_strlenしてみましょう
mb_strlenした結果 • 1文字のハズなのに、4とでましたね – つまり、4つのコードポイントがあるということになります – mb_str_splitもしてみましょう
mb_str_splitした結果 このように、4つのコードポイントに分かれていること がわかりますし、 と♂が別れています 🙇
コードポイントとは • UnicodeでいうコードポイントとはU+1234などと 記す符号位置で、16進数で表します • mbstringではこの単位で測っていきます
コードポイントは? 2コードポイント目がU+200D、4コードポイント目 がU+FE0Fです
それぞれの意味 • U+200Dはゼロ幅接合子などと呼ばれてお り、Zero Width Joinerの略でZWJと言います • U+FE0Fは異体字セレクタと言い、U+FE00から U+FE0Fまでの範囲16文字を使って絵文字のバリ エーションを表現します
• https://www.unicode.org/glossary/#variation _selector
異体字セレクタについて • 漢字でも使われています – Ideographic Variation Sequence(漢字(表意文字)異体 字シーケンス、IVS)と呼ばれています – 範囲はU+E0100からU+E01EFです
– 組み合わせを定義するのがIVS、字形を定義するデータ ベースをIVD(Ideographic Variation Database)といいま す – https://www.unicode.org/reports/tr37/
漢字の異体字セレクタについて • 例えば「邉」 CJK UNIFIED IDEOGRAPH-9089 – https://glyphwiki.org/wiki/u908a-ue0104 – https://747.codeberg.page/vsselector/#!/ja/9089
– 邉 邉󠄀 邉󠄁 邉󠄂 邉󠄃 邉󠄄 邉󠄅 邉󠄆 邉󠄈 邉󠄉 邉󠄊 邉󠄋 邉󠄌 邉󠄍 邉󠄎 … • 游ゴシック体で表示させました • すべて違う異体字です • 同じ漢字に見えるのもあれば違うのもありますね
絵文字に戻っておさらいしましょう
mb_str_splitした結果 見えないほうはそのようにちがうわけですね ゼロ幅接合子 (ZWJ) U+200D (絵文字の)異体字セレクタ U+FE0F
どうすれば1文字として測れますか?
ICUというライブラリを使います • Grapheme cluster(グラフィム、書記素クラスター)単位で測れば 良い – それを格納しているのがICU – 結局データベースから測らないといけないのです •
PHPではintl拡張に入っています – --enable-intlとしてコンパイルしましょう – grapheme_strlenを使えば測れます • https://www.php.net/grapheme_strlen
PCRE(preg系関数)も使えます • PCREも書記素クラス ター単位での検出がで きます • \Xを使用します • https://www.pcre.or g/original/doc/html/
pcrepattern.html
grapheme_strlenした結果 このようにして、書記素クラスターを正しく数えるこ とができるわけですね
濁音・半濁音の場合
本来の濁音と半濁音 • JIS X 0201ではガのように文字と濁音が別々(いわゆる半角カ ナ) • JIS X 0208ではガのように、独立した文字も収録された
• Unicodeでは独立した文字も別にできたりする – ガが果たしてU+30ACなのか、U+30ABとU+3099の両方なのかが一見 するとわからない – それを統一するのが「正規化」と呼ばれる
正規化の方法 • 正規化方式D(NFD) – $ sapi/cli/php -r 'var_dump(Normalizer::normalize("ガ", Normalizer::NFD));' string(6)
"ガ" # カと濁音が分割されている • 正規化方式C(NFC) – $ sapi/cli/php -r 'var_dump(Normalizer::normalize("ガ", Normalizer::NFC));' string(3) "ガ" • 正規化方式KD(NFKD) – $ sapi/cli/php -r 'var_dump(Normalizer::normalize("ガ", Normalizer::NFKD));' string(6) "ガ" # カと濁音が分割されている • 正規化方式KC(NFKC) – $ sapi/cli/php -r 'var_dump(Normalizer::normalize("ガ", Normalizer::NFKC));' string(3) "ガ" • PHPではintlの Normalizerクラスを使 います • 正規化方式も4種あるの でその時適切な正規化 方式を選択する必要が あります
正規化で戸惑う例 • 例えばハングルの「アニョハセ ヨ」(こんにちは)を正規化 D(NFD)をすると、ハングルの 音節がバラバラに分解されて しまいます(ちゃんと表示できる 場合もありますが) • 参考:
https://www.unicode.org/c harts/normalization/ \
まとめ • Unicodeにはバージョンがあることがわかりました • バージョンによって絵文字が表示されないことがわかりました • ZWJ、異体字セレクタなどで必ずしも1コードポイントに収まらないことがわかりました • 濁音・半濁音は色々な方法の組み合わせがあることがわかりました •
PHPのUnicodeの対応具合がわかりました – mbstringでは1コードポイントごと、intlとPCREでは書記素クラスターとして測れる • 正規化は複雑すぎる、触れないでおければ幸せ • Unicodeは知ることが多いことがわかり、わからないことがわかりました – たとえば、不正なバイトシーケンスとか喋ってないですね? – あなたが知っていることがあったら、教えてください!
提案 • PHPのGrapheme関数には、文字列の処理関数が少ないように見 えます • 少なくとも、mb_str_split相当の書記素クラスターごとにarrayで返 却できるとarray関数で処理できてよいのではと思いますがどうで しょう? • つまり、grapheme_str_splitが必要なのではないかということです
– 絵文字などを「一文字」として配列として分割するというものです – RFCを作りました https://wiki.php.net/rfc/grapheme_str_split
参照 • http://www.unicode.org/L2/L2016/16181-gender-zwj-sequences.pdf • https://ja.wikipedia.org/wiki/%E3%82%BC%E3%83%AD%E5%B9%85%E6%8E%A5 %E5%90%88%E5%AD%90 • https://www.unicode.org/glossary/#variation_selector • https://www.unicode.org/glossary/#ideographic_variation_sequence
• https://www.unicode.org/reports/tr37/ • https://ja.wikipedia.org/wiki/%E7%95%B0%E4%BD%93%E5%AD%97%E3%82%B B%E3%83%AC%E3%82%AF%E3%82%BF#%E7%A8%AE%E9%A1%9E • https://emojipedia.org/ja/emoji-15.0 • https://747.codeberg.page/vsselector/#!/ja/9089 • https://glyphwiki.org/wiki/u908a-ue0104 • https://www.php.net/grapheme_strlen