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
文字数の話 〜Unicodeの楽しい話〜
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
しゅん🌙
July 02, 2023
Programming
0
270
文字数の話 〜Unicodeの楽しい話〜
プログラミングをする際に間違えがちな文字数のカウント方法について,Unicodeの仕組みを紐解きながら解説しています.
しゅん🌙
July 02, 2023
Tweet
Share
More Decks by しゅん🌙
See All by しゅん🌙
エンジニアのための”最低限いい感じ”デザイン入門
shunshobon
0
190
Rustで対戦型Tetrisを作った話
shunshobon
0
400
文字数の話の続き 〜Unicodeの楽しくない話〜
shunshobon
0
240
Haskellの並列・並行処理
shunshobon
1
430
Other Decks in Programming
See All in Programming
プロダクトオーナーから見たSOC2 _SOC2ゆるミートアップ#2
kekekenta
0
120
re:Invent 2025 のイケてるサービスを紹介する
maroon1st
0
170
0→1 フロントエンド開発 Tips🚀 #レバテックMeetup
bengo4com
0
520
ZJIT: The Ruby 4 JIT Compiler / Ruby Release 30th Anniversary Party
k0kubun
1
390
AI によるインシデント初動調査の自動化を行う AI インシデントコマンダーを作った話
azukiazusa1
1
580
Python札幌 LT資料
t3tra
7
1.1k
AIエージェント、”どう作るか”で差は出るか? / AI Agents: Does the "How" Make a Difference?
rkaga
4
1.9k
ゆくKotlin くるRust
exoego
1
210
組織で育むオブザーバビリティ
ryota_hnk
0
150
実は歴史的なアップデートだと思う AWS Interconnect - multicloud
maroon1st
0
360
LLM Observabilityによる 対話型音声AIアプリケーションの安定運用
gekko0114
2
400
IFSによる形状設計/デモシーンの魅力 @ 慶應大学SFC
gam0022
1
270
Featured
See All Featured
Leo the Paperboy
mayatellez
4
1.3k
So, you think you're a good person
axbom
PRO
2
1.9k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.1k
Making Projects Easy
brettharned
120
6.6k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
0
120
The Mindset for Success: Future Career Progression
greggifford
PRO
0
220
The Curious Case for Waylosing
cassininazir
0
230
Typedesign – Prime Four
hannesfritz
42
2.9k
WENDY [Excerpt]
tessaabrams
9
36k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
61k
Evolving SEO for Evolving Search Engines
ryanjones
0
110
Transcript
文字数の話 Unicodeの楽しい話
自己紹介 名前: しゅん Twitter: @shun_shobon / GitHub: @shun-shobo1
学校: 長野高専 電子情報工学科 5 得意: Web Frontend / Web Frontend Ops / A11y なI 研究: ホログラフィ・ヒューマンインタフェースなI 趣味: PCゲーム・自作キーボー 一言: コンピュータと人との関わり方を模索しています
突然ですがクイズです
このJSのコードは何を出力する?
答え
このJSのコードは何を出力する?
答え どう見ても11文字しかないのに出力は12......
今回はこの挙動を理解しよう! というコンセプトです
Unicodeの仕組み
Unicodeの目的 Unicodeは全ての文字にユニークなIDを降ること目的としている. このユニークなIDのことをUnicodeでは Code Point(コードポイント) と呼ぶ. チ → U+30C1 ゃ
→ U+3083 𠮟 → U+20B9F ! → U+FF01
Code Pointの符号化方法 このCode Pointを相手に送る際には,特定の方式によってバイナリにすることで送信される. これにはいくつかの方式がある. UTF-32 … どのCode Pointも4Byteで表r
UTF-16 ... 小さなCode Pointは2Byte,大きいのは4Byt UTF-8 ... なるべく小さなByteになるように1〜4Byteで表す ※ものすごい雑な解説なので詳しくは調べてください
符号化の例① 試しに「チ(U+30C1)」をそれぞれの形式で符号化すると... ※UTF-32・UTF-16はビッグエンディアンでの場合 g UTF-32 … 0x00, 0x00, 0x30, 0xCb
g UTF-16 ... 0x30, 0xCb g UTF-8 ... 0xE3, 0x83, 0x81
符号化の例② 試しに「𠮟(U+20B9F)」をそれぞれの形式で符号化すると... I UTF-32 … 0x00, 0x02, 0x0B, 0x9V I
UTF-16 ... 0xD8, 0x42, 0xDF, 0x9V I UTF-8 ... 0xF0, 0xA0, 0xAE, 0x9F ※UTF-32・UTF-16はビッグエンディアンでの場合
先程の挙動の解説
JavaScriptでの内部表現はUTF-16 JavaScriptでは仕様として文字列データの内部表現をUTF-16と定めている. このようなコードを実行した際,メモリ上に保存されるデータはCode Pointがそのまま保存 されるわけではなく,それをUTF-16で符号化した「0xD8, 0x42, 0xDF, 0x9F」が保存され る. →
つまり1要素2byteの配列で管理される
.lengthの挙動 .lengthはこの2byte配列の要素数を数えているだけ 4byteで表現される「𠮟」があるため,11文字だけど要素数が12なので.lengthは12を返す.
解決策
StringのIteratorを使う Stringがネイティブに実装しているIteratorの処理はCode Point単位で処理される. IteratorベースのSpread演算子を使えばCode Point単位に文字列を分割できる!
よし!これで文字数のカウ ントはバッチリだ!
...本当に?
1Code Point = 1文字 ではない
異体字セレクタという存在 Unicodeには漢字や絵文字のバリエーションを表す異体字セレクタというものがある. 例えば「葛」と「葛󠄀」の違いや,「 」と「 」の違いなど. つまりCode Pointの数と直感的な文字数が一致しない場合がある. これらは基本となる文字にCode Pointを定義して,その文字の後に異体字セレクタという別 のCode
Pointをつけることによって表現される.
結合文字という存在 意味的にはこの2つは等しいため,検索などでこの2つを異なる扱いをしてしまうと,直感に 反する可能性がある. Unicodeには結合文字という,複数のCode Pointを使って1文字を表現することがある. 例えば「が」は,「U+304C」と「U+304B, U+3099」の2通りの表し方がある.
絵文字の合字 合字とは「f」を2回重ねたときに「ff」のように2つがくっついた状態で表示されること. 一部の絵文字はこの合字を利用して複雑な絵文字を表現している場合がある. それぞれの絵文字の間にZero Point Joiner(U+200D)という不可視の文字を入れることに よってその絵文字は合成されているということを表す. ※Zero Point Joinerを使わないで合成される場合もあり(一部の国旗の絵文字など)
こんなのいちいち判別するプ ログラムなんて書けるか!
書けます
書記素クラスタと JSの便利なAPI
自然な区切りを表す書記素クラスタ これまで見てきたように,Code Point単位で見ても異体字セレクタや結合文字,合字などの 概念によってUnicodeにおける「1文字」というのはかなり表現するのが難しい. それに「1文字」という表現は非常に曖昧で,Byte単位なのか,Code Point単位なのか, 「いわゆる直感的な1文字」なのかが分かりづらい. そこで,「いわゆる直感的な1文字」をUnicodeでは書記素クラスタと呼んでいる. 書記素クラスタでの分割アルゴリズムはUnicodeの仕様として標準化されており,この仕様 に従えば誰でも直感的な1文字で文字列を分割することができる(とはいえアルゴリズムは非
常に複雑).
JSの便利なAPI,Intl.Segmenter() 書記素クラスタへの分割をJavaScriptでやる場合,ECMAScript標準APIである Intl.Segmenter()が使える. これを使うと文字列をロケールに応じて書記素,単語,文に分割することができる.
これでようやく正しく 「文字数」を 数えることができる
まとめ
まとめ n Unicodeにおける文字一つ一つに割り当てられるユニークなIDを Code Point と言g n JSでは文字列の内部表現がUTF-16で統一されていh n .lengthはCode
Point単位の処理ではないので,直感と異なる値を返す事があh n Code Point単位で得たい場合はIteratorを使g n Unicodeでは「1Code Point = 直感的な1文字」とは限らな6 n 異体字セレク n 結合文 n 絵文字の合 n et n 直感的な1文字のことをUnicodeでは 書記素クラスタ と呼Æ n JSでは Intl.Segmenter() を使うと簡単に書記素クラスタ単位に分割できる