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
mb_trim関数を作りました
Search
てきめん tekimen
PRO
May 11, 2024
Programming
1.4k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
mb_trim関数を作りました
PHPカンファレンス香川の資料です #phpconkagawa
てきめん tekimen
PRO
May 11, 2024
More Decks by てきめん tekimen
See All by てきめん tekimen
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
840
ChatGPTを使ってRaspberry Pi Picoの処理系を書いた
youkidearitai
PRO
0
96
PHP Internals わいわい #3 PIEを使ってみよう
youkidearitai
PRO
0
73
grapheme_strrev関数が採択されました(あと雑感)
youkidearitai
PRO
1
350
Limit of code point for grapheme cluster in programming language side.
youkidearitai
PRO
0
95
Unicodeどうしてる? PHPから見たUnicode対応と他言語での対応についてのお伺い
youkidearitai
PRO
2
3.6k
PHP 8.5の裏話
youkidearitai
PRO
0
160
CJK and Unicode From a PHP Committer
youkidearitai
PRO
0
350
PHP Internals わいわい #3 mb_*関数を作ってみよう
youkidearitai
PRO
0
170
Other Decks in Programming
See All in Programming
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
1
270
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1k
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
440
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
520
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
1
3.3k
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
200
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
200
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
320
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
200
継続モナドとリアクティブプログラミング
yukikurage
3
670
PostgreSQL 18で考えるUUID主キー
kazuhiro1982
0
450
PHP初心者セッション2026 〜生成AIでは見えない裏側を知る:今だからLAMPを通して仕組みを学ぶ〜
kashioka
0
780
Featured
See All Featured
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.7k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
330
SEO for Brand Visibility & Recognition
aleyda
0
4.6k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
230
Done Done
chrislema
186
16k
The Curious Case for Waylosing
cassininazir
1
440
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
500
Transcript
mb_trimを作りました
自己紹介 てきめん • https://tekitoh-memdhoi.info • X: @youkidearitai • https://github.com/youkideari tai
• PHP 8.4で複数の関数を作った – mb_trim – mb_ucfirst、mb_lcfirst – grapheme_str_split オレ
遡ること2022年 • とあるFeature request(機 能追加のリクエスト)が来る • それがマルチバイト対応の trim関数を作ってくれない かというもの •
しかし、実装してくれる人が 現れず…
そのときのてきめんの状況 • 2022年8月はまだ8.1でmbstringが変わると認識 してなかった • 2022年12月からmbstringのレビュー作業に加 わった • mb_trimのfeature requestは認識してた
時は流れ • 2023年9月、ぼくがこの Feature requestを拾う – このころのぼく は、mbstringのレビュー も一通り落ち着いて余力 があったことが大きな要
因
実装するしかない! • もう自分でRFC書いた ほうがいいよと言われる • 皆もmake sense(理に かなってる)と言ってる 以上、もうしない理由が なかった
RFCの草案をもらう • 8ctopusさんが草案を書い てくれてた • こちらを参考に、ちょっと修 正 – mb_ltrimとmb_rtrimを追 加
– $encodingを追加
PHP Internalsへ投稿 • 8ctopusさんが internalsメーリングリ ストへメールを送れな かったことから、代理で 「ぼくもほしいのでどう 思う?」と送ってみた
PoCの作成 • 概念実証コードを作成 し、プルリクエストにしま した – この時点では、Draft pull requestとしました
RFCを記述するWiki Karma Request • RFCを記述するのが初めてだったので、まずアカウントを作り ます • アカウントを作ったら、Internalsメーリングリストへ「RFC Karma Request」を投げます
– タイトルはこのままで「〇〇したいです」を添えれば大体許可さ れます – 許可されたらWikiの編集権をもらえます
RFCの作成 • RFCを作成していきます • Wikiなので、空いてるURLに記述できます – 今回は https://wiki.php.net/rfc/mb_trim としました •
先程の中身を記述していきます
RFCの考慮 • RFCは他人にわかるようにいろいろなことを考えま す • 一番考えたのは$encodingの部分でした – trim関数には「..」という、範囲を指定する表記法がある のですが、これを実現するのは不可能に思いました •
というのも、文字コードごとに範囲が違いますし、Unicodeが 広すぎるのも問題です
RFCをInternalsメーリングリストへ送信 • メーリングリストへ送信して、議論します • この状態になったら、RFCを「Under Discussion」 にします – Under Discussionを少なくとも2週間続けます
• ただ、議論のすべてに答えることが必要でその合意形成に1 年とか経ったりするものもたくさんあったりします
Votingに入る • 投票フェーズに入ります • 期間は2週間+αを置きます • ここで2/3のYesを貰えれば可決(Accepted)となり ます • mb_trimはここで可決をもらいました
そして実装へ • 先程のプルリクエストを普通のプルリクエストにし ます • レビューを受けます – ここが結構おもしろかった
めっちゃアツいレビュー • 主にnielsdosさ ん、alexdowadさんか らレビューを受ける
128コードポイント以上の対応 • $stringが128コードポ イント以上の処理に対 応してないよとレビュー を受ける – そういえばそうだった
解決策が思い浮かばない、寝る • 色々と試行錯誤してた けどむずくて無理!JST だともう寝る時間だ寝 るってなっててnielsdos さんに教えを請うすが た – 似たような実装で解決
コードポイントって何 • Unicodeにおけるコードポイントとは、U+xxxxの xxxxの部分で、0x0から0x10FFFFの16進数が入る – https://www.unicode.org/glossary/#code_point – 何らかの文字がここに割り当てられるのでこれを1文字 として数える事が多い
線形探索以外になんかあるの!? • $charactersを1コードポイ ントずつ線形(O(N))に探索 してたらここはHashTable を使えばいいよと教えを請 う – 最初、どういうこと?ってなっ てnielsdosさんに聞いてる
ぼく
HashTableでO(1)にする • HashTableのキー部分に コードポイントをあてがうと いうテクニック(値はなん でもいい)でO(1)にすると いうテクニックを教えても らった – すげえ!ってなった
ハッシュテーブル(HashTable)ってなに • キーにハッシュ関数を与えてあげて、一意 のアドレスに値を格納・取り出すデータ構 造 – ハッシュ関数というくらいですから、md5と かsha1とかでもいいのです • 衝突を気にしなければO(1)で済ませられ
る – 衝突が絡むとO(N)になったりするけど今 回は衝突を考える必要はなかった • php-src では HashTable という構造体 が用意されている
さっきから言ってるO(N)とかってなに • 計算量、オーダーのこと • O(N)はN個あったら最悪N回計算し ないといけないことを示す – 0個では0回 – 線形探索がこれ
• O(1)は何個あっても1回で済む – 0個でも1回だけど – ハッシュテーブルはこっち
XORによるビット演算のテクニック • 左側のtrimが終わった らフラグをfalseにして たけど、mode自体を XORすればフラグ消せ るよと教えられる – すげー!ってなりました
ついにapprovedをもらう • nielsdosさんによるapproved をもらう – すごくお世話になりましたマジで ありがとうございます • alexdowadさんに「squashし てもらっていい?」ということで
git rebase -i とgit push – forceする – php-srcではsquashでひとまと めにしてます
Landed on master • NEWSの追 加、UPGRADINGの追 加などをしてマージと いうかsquash commitされました
Optimizations for mb_trim #12803 • nielsdosさんがmb_trim 関数のパフォーマンス調 整をしてくれて、 4文字 (コードポイント)までは線
形探索したほうが速いとわ かった – O(1)が0個でも1回計算し なきゃならないところもあり うる
Build failed at mbstring_arginfo.h on Windows(Visual C++) #13789 • Windowsの日本語のVisual
C++でビルドができないという 問題を(あの)廣川さんから メールでもらう – $charactersをUTF-8バイト列 でコンパイルしていたのが問 題 – コンパイル時のフラグにUTF- 8であることを加えることで対 処
mb_trim() inaccurate $characters default value #13815 • mb_trim関数群で文字コードが UTF-8じゃないときにtrimしない というIssue
– inaccurateが「正しくない」なの で、最初なんのことかわからな かった… – 結局、$charactersを決め打ちし てるのがよくないので、NULLが 正しいのでは?となる
Fix GH-13815: mb_trim() inaccurate $characters default value #13820 • nielsdosさんによるプルリク
エスト – $charactersをNULLにしま しょうというプルリクエスト – ただし、RFCの内容を書き換 えるためPHP Internalsで議 論する必要になり議論を行っ た
mb_trimのデフォルト値変えてもいい? • PHP Internalsメーリングリストで、mb_trimのデフォルト 値を変えてもいいかと質問してみる • 変えるしかないならそれでいいのではという意見 • RFCは必要ないとの意見をもらう •
ぼくは色々ごちゃごちゃ動いてた – mb_trimのRFC書き換えて怒られた(?)り、戻したり
結果として書き換わりました • $charactersはデフォルト値NULLとなり、NULLのとき にRFCで決まっていたコードポイントを削除するように なりました • mb_trim($str, encoding: “Shift_JIS”); などのときに
正しく削除できるようになりました • こういう設計ミスがあったときに参考にしてもらえれば
使い方 • mb_[lr]?trim関数はいわゆる全角スペース(U+3000)もtrimできます – PCREで言うところの\sなどをサポートしています • ユースケースの一つとして、mb_ltrim関数を使ってUTF-8 BOMを削除できます – mb_ltrim($str,
“\u{FEFF}”); • 例えばmb_substrでZero Width Joiner(ZWJ)を含む絵文字などでZWJが残ったと き、mb_rtrim関数を使ってZWJを削除できます – mb_substr(mb_rtrim(“ ”, “\u{200D}”), 0, 2); 🙇♂️ • 複数の文字(コードポイント)にも対応してます – mb_trim($str, “ \n\r\u{200D}\u{FEFF}”); • もちろん、他の文字エンコーディングにも対応しています – mb_trim($str, encoding: “shift_JIS”); • マニュアルはPHP 8.4に合わせて書き出すと思います
まとめ • mb_trim、mb_ltrim、mb_rtrim関数を作りました – どんなタイミングで作ったのかを説明しました • PHP Internalsとのコミュニケーションについて説明しまし た •
レビューを経てめちゃくちゃすごく勉強になりました • PHP 8.4で入るこれらの関数をお楽しみに
Appendix: mb_trimのアルゴリズム • 1コードポイントごとに左から右へ処理をしていく • 128コードポイントごとにto_wcharメソッドが呼び出される • 左側にtrimする文字があればleftを1足す • 左側のtrimする文字がなければ右側のtrimに移るため、フラグを
rightへの処理にするため、XORでMB_RTRIMに変更 • 右側にtrimする文字があればrightを1足す • 右側にtrimする文字がなければrightを0にリセット • 下記のような擬似コードでmb_substrする: – mb_substr($str, left, mb_strlen($str) – (right + left));