VIDEO LESSON
JavaScriptのIntl.Segmenter.segment():絵文字を壊さず文字数を数えるの解説動画
再生時間 7:43動画を別のタブで開く ↗
動画の字幕・文字起こしを読む
再生中の字幕を濃い黒で表示し、一番上に追従します。字幕の行を選ぶと、その位置から再生できます。
- 0:00こんにちは。
- 0:00今回はジャバスクリプトのインターナショナル・セグメンターのセグメントを紹介します。
- 0:07入力欄の文字数表示やタイトルの短縮で困るのが、利用者が感じる一文字と、プログラムが数える一文字のずれです。
- 0:15笑顔の絵文字は見た目では一つでも、内部では別の数え方をされますし、濁点やアクセントが付いた文字は、
- 0:20切り方を間違えると途中でちぎれてしまいます。
- 0:25セグメントは、文字のまとまりを壊さずに文字列を分けるための仕組みです。
- 0:30この動画では、見た目の文字数を正しく数える方法と、まとまりを保ったまま短くする方法を、
- 0:35実行結果と一緒に学びます。
- 0:39まず、数え方の違いを整理します。
- 0:41文字列のレングスは、ユーティーエフ十六のコード単位という細かい単位で数えます。
- 0:48笑顔の絵文字はこの単位では二つ分になるため、レングスは見た目より大きくなります。
- 0:54次に、文字列を点三つで広げて配列にする方法は、コードポイントという単位で数えます。
- 1:00絵文字は一つにまとまりますが、英字にアクセントを合成した文字は、英字とアクセントの二つに分かれてしまいます。
- 1:09そこで登場するのが書記素クラスタです。
- 1:12これは利用者が一文字と認識するまとまりの単位で、合成された文字も一つとして扱えます。
- 1:18どの単位で数えるかで結果が変わる点が、このテーマの出発点です。
- 1:23動作環境を確認します。
- 1:25インターナショナル・セグメンターは、二千二十四年四月に主要ブラウザーで使えるようになった比較的新しい機能です。
- 1:33クロームとエッジは八十七以降、ファイアフォックスは百二十五以降、サファリは十四点一以降が目安です。
- 1:40ノード・ジェイエスでも使え、記事の実行対象は二十二系または二十四系です。
- 1:46画面要素には依存しないので、ブラウザーとノードで同じコードが動きます。
- 1:51ただし古いブラウザーやアプリ内の画面では未対応のことがあります。
- 1:55実行前に、セグメンターが使えるかどうかを必ず確認してください。
- 2:00ノードでは国際化データの構成によっても結果が変わる点に注意が必要です。
- 2:05基本の書き方です。
- 2:06まずニューでインターナショナル・セグメンターを作ります。
- 2:10第一引数はロケールで、日本語ならジェイエーを指定します。
- 2:14第二引数のグラニュラリティーにグラフィームを指定すると、書記素単位で分ける設定になります。
- 2:21この設定が既定値でもあります。
- 2:23作った分節器のセグメントに対象の文字列を渡すと、セグメンツという反復できるオブジェクトが返ります。
- 2:30配列でも文字数でもない点がポイントです。
- 2:32繰り返しで取り出すと、各要素には、切り取られた文字列、その開始位置、元の文字列全体が入っています。
- 2:39開始位置は書記素の通し番号ではなく、ユーティーエフ十六単位で数えた位置なので注意してください。
- 2:46数えるときは、セグメンツを配列に変換するのが便利です。
- 2:50アレイ・フロムの第二引数に関数を渡すと、各要素からセグメントだけを取り出して配列にできます。
- 2:58その配列の長さが、そのまま書記素の数になります。
- 3:02空の文字列を分けると要素はゼロ個なので、答えはゼロです。
- 3:07元の文字列を直接書き換える処理ではないため、入力はそのまま保たれます。
- 3:12カウントと短縮で同じ分節器を使い回すと、数え方に一貫性が出ます。
- 3:18関数にまとめる場合は、入力が文字列かどうかを最初に確認し、違う型ならタイプエラーを投げる形にすると、
- 3:23呼び出し側の間違いに早く気付けます。
- 3:29記事の中心となる実行例を読みます。
- 3:31対象は、大文字のエー、アクセント付きのイー、笑顔の絵文字、大文字のビーをつないだ文字列です。
- 3:39ユーティーエフ十六の単位数は六、コードポイント数は五でした。
- 3:43ところが書記素の数は四つです。
- 3:45アクセント付きのイーは二つのコードポイントからできていますが、一つのまとまりとして数えられているからです。
- 3:54分節結果は、エー、アクセント付きのイー、絵文字、ビーの四つでした。
- 3:59各要素の開始位置はゼロ、一、三、五です。
- 4:02途中に二単位ぶんを使う文字があるため、位置が飛んでいる点にも注目してください。
- 4:08これらの出力はノード・ジェイエスの実機でも同じになることを確認済みです。
- 4:13次に、まとまりを保ったまま短くする関数です。
- 4:17まず文字列を書記素の配列に分け、要素数が上限以下なら元の文字列をそのまま返します。
- 4:24上限を超える場合だけ、先頭から上限の数だけ要素を取り出してつなぎ、最後に省略記号を付けます。
- 4:31例えば上限を二にすると、先頭の二書記素に省略記号が付いた結果になります。
- 4:37ここで注意したいのは、上限は省略記号を除いた数だという点です。
- 4:42省略記号も含めて全体の上限を決めたい設計では、その一文字ぶんをあらかじめ差し引いてください。
- 4:49また上限の値は、ゼロ以上の整数であることを確認し、違う場合はレンジエラーを投げる形にしています。
- 4:57失敗例を見ます。
- 4:58アクセント付きのイーを、点三つで広げる方法で先頭だけ取り出すと、残るのは英字のイーだけで、
- 5:03アクセントが落ちてしまいます。
- 5:08見た目がわずかに変わるだけなので、テストで英数字しか使っていないと見逃しやすい失敗です。
- 5:14一方、セグメンターで書記素単位に分けてから先頭を取り出すと、アクセントまで含めた一文字がそのまま残ります。
- 5:23家族の絵文字や国旗の絵文字のように、複数の絵文字が合体して一つに見える文字でも同じことが起きます。
- 5:30切り出しや数え直しを行う処理では、単位の選び方が結果を左右します。
- 5:36例外と未対応への対処です。
- 5:38グラニュラリティーに無効な値を指定すると、コンストラクターがレンジエラーを投げます。
- 5:44またセグメンターはニュー付きで作る必要があり、省略するとタイプエラーになります。
- 5:50ここで混同しやすいのが、自作関数が入力チェックのために投げるタイプエラーです。
- 5:56これはエーピーアイ自体の仕様ではなく、自分の関数のルールとして分けて考えてください。
- 6:03処理は同期的で、プロミスは返らないため、アウェイトは不要で、例外はトライキャッチで受けます。
- 6:10未対応の環境では、数え方の違う方法へ黙って切り替えるより、対応環境を案内するほうが、
- 6:14文字数のルールを守れます。
- 6:19活用場面を見ましょう。
- 6:20プロフィール名の文字数カウンターでは、利用者が感じる文字数と表示をそろえられます。
- 6:27通知文や一覧タイトルのプレビューを短くするときも、絵文字やアクセント付き文字を途中で壊さずに切り取れます。
- 6:35分節単位は書記素だけではありません。
- 6:38ワードを指定すると単語単位、センテンスを指定すると文単位に分けることもでき、
- 6:43日本語の文章でも単語のまとまりを取り出せます。
- 6:47用途に応じて単位を使い分けてください。
- 6:50大切なのは、数える処理と切り取る処理で、必ず同じ分節器と単位を使うことです。
- 6:56単位がずれると、上限ぴったりのはずの文字列がはみ出すといった不整合が起きます。
- 7:02制約とまとめです。
- 7:03書記素の数は、ユーティーエフ八のバイト数でも、画面に表示したときの横幅でもありません。
- 7:10保存容量の制限やレイアウトの幅を調べたいときは、それぞれ別の方法で測ってください。
- 7:15また分節しても文字列が正規化されるわけではなく、元の表現はそのまま保たれます。
- 7:21ユニコードや国際化データの更新で、新しい絵文字の扱いが環境ごとに変わる可能性もあります。
- 7:27ブラウザーのカウントは入力の補助として使い、保存時の最終判定はサーバー側で行う設計が安全です。
- 7:34文字を数える、切り取る場面に迷ったら、まずセグメンターで書記素に分ける。
- 7:39この流れをぜひ活用してください。
- 7:41お疲れさまでした。
この動画で学べること
Intl.Segmenter.segment()で絵文字や結合文字を分断せずに数え、短縮する方法を解説。引数・戻り値、ブラウザーとNode.jsでの実行手順、期待出力と互換性の制約を学べます。
解説記事・サンプルコードを読む:JavaScriptのIntl.Segmenter.segment():絵文字を壊さず文字数を数える →