DESIGN / CODE / INFRA / AI

解説

AIに指定した文字数が合わない?文字列の長さと見た目の文字を分けよう

同じ文章でもUTF-16・コードポイント・書記素・UTF-8で数が違う。絵文字と結合文字を使い、文字数の条件を明確にする方法と動く作例。

AIに指定した文字数が合わない?文字列の長さと見た目の文字を分けよう
保存リストを見る →
この記事の道しるべ 5項目

AIへ「3文字にして」と頼んだのに、投稿フォームでは制限を超えた。同じ文字列でも、どの単位で数えるかによって結果が違うことがあるよ。

今回はAIモデルを呼ばず、固定の短い文字列をブラウザで数える。文字数の指定と、実際の投稿先での確認を対応させるための作例だよ。

JavaScriptのlengthは、見た目の文字数とは限らない

JavaScriptの文字列はUTF-16で扱われ、lengthはコード単位を数える。一部の絵文字は二つのコード単位になり、見えている一文字と一致しない。

さらに、かに濁点を組み合わせるような表し方では、複数のコードポイントで一つのまとまりを作れる。コードポイントはUnicodeの符号位置、書記素は利用者が一文字として扱うような文字のまとまりを数える単位だよ。

同じ文字列を三通りで数える

const text = "A😀か\u3099";
console.log(text.length); // 5: UTF-16コード単位
console.log([...text].length); // 4: コードポイント
console.log([...new Intl.Segmenter("ja", {
  granularity: "grapheme"
}).segment(text)].length); // 3: 書記素

この文字列はA、絵文字、かと結合する濁点という構成。最後の二つのコードポイントは、見た目では「が」のようなまとまりになる。

3と5のどちらか一方が、あらゆる用途の正解というわけではない。投稿先がどの方式で制限を判定するかを確認することが必要だね。

バイト数も別の数

作例ではUTF-8へ変換したときのバイト数も表示する。最初の例は11バイト。これは保存や通信で使う容量の単位で、文字数そのものではないよ。

日本語、絵文字、英字を同じ一文字として表示していても、符号化したときのバイト数が同じになるとは限らない。文字数制限と、データ容量の制限を混ぜないようにしよう。

作例で、絵文字と結合文字を比べる

  1. 最初の文字列で、5・4・3・11という四つの値を見る。
  2. 結合したアクセントや家族の絵文字を選び、数え方による違いを比べる。
  3. 元のコードポイントの一覧で、見えない結合用の文字も確認する。
  4. 「最初から試す」で最初の文字列へ戻す。

作例は元の文字列を勝手に正規化しない。Intl.Segmenterへ未対応のブラウザでは、書記素の計算を未対応と表示する。使うUnicodeの版などによる差もあり得るので、投稿先と完全に同じ判定だと決めつけないでね。

AIへの条件を、数え方まで書く

例えば「本文だけ、空白と改行も含め、投稿先の文字数表示で100以内。超えた場合は削れる候補も示す」と、対象と確認先を明確にする。

ただし、AIが「100文字です」と自己申告したことだけでは確認にならない。最終的な文章を、投稿先や同じ数え方の確認プログラムで数え直そう。URLなどへ独自の重みを付けるサービスでは、そのルールも別に必要になるよ。

編集部ではNode.jsとChromiumで固定の文字列の各単位とリセットを確認した。AIの文字数遵守率を測った結果ではないよ。変換の意味はUnicode正規化、AIが処理する別の単位はトークンと文字数も参考になるね。

動かしてみよう:文字の数え方を比較

固定の文字列でコード単位・コードポイント・書記素・バイト数を比べよう。

参考・出典

公開と変更の記録
  • :初回公開

日時は日本時間です。記載のある変更は、確認できた編集記録に基づきます。更新日の違いだけから変更内容を推測して載せることはありません。

更新・訂正の方針 →

みんなのコメント 0

感想や、試してみたことを聞かせてね。コメント・返信は承認後に公開されます。

最初のコメントをどうぞ。