1 文字列長の基本概念

1.1 文字列長の定義

文字列長とは、ある文字列を構成する要素数を表す指標である。プログラミングでは「長さ」は通常、文字列を内部表現として扱う際の単位(バイト、符号化単位、コードポイント、グラフェムなど)に対応して決まる。したがって、同じ見た目の文字列でも、どの単位で数えるかにより数値が変わり得る点が本質となる。

1.2 何を「長さ」として数えるか

1.2.1 バイト数としての文字列長

バイト数としての長さは、符号化されたバイト列の総数を意味する。文字コードがUTF-8のように可変長方式の場合、同じ「文字数」に見える内容でもバイト列の長さは一定にならない。ネットワーク送信量の見積もり、ストレージ容量、低レベルなI/Oといった場面では、この定義が扱いやすい。

1.2.2 コードポイント数としての文字列長

コードポイント数としての長さは、Unicodeのコードポイントの個数を数える方法である。Unicodeでは多様な文字がコードポイントに対応付けられるため、異なる符号化形式(UTF-8, UTF-16, UTF-32等)でも論理的に同じ内容を比較しやすい利点がある。ただし実装によっては、内部表現が異なるため「コードポイント数」を取得するために追加の走査が必要になることがある。

1.2.3 ユーザー認識の文字数(グラフェム数)

ユーザーが「1文字」と認識する単位は、しばしばUnicodeのグラフェムクラスタ(表示上ひとまとまりとして扱われる単位)に対応する。たとえば合成文字(基底文字と結合用の符号)や、複数コードポイントからなる絵文字列では、コードポイント数と見た目上の文字数が一致しないことがある。グラフェム数を「長さ」とする定義は、UIのカーソル移動や文字数制限など、対人向けの振る舞いで重要になる。

1.3 文字コードとの関係

文字列長は、文字コードと密接に関係する。符号化方式が可変長である場合、バイト長は文字内容に依存して増減する。さらにUnicodeのような体系では、同一視される文字列(正規化による同値、表示上の同一性)でも内部のコードポイント列が異なる場合がある。そのため「何を長さとするか」を先に決め、文字コードの前提を明確にすることが実務上の前提となる。

2 実装における測定方法

2.1 文字列長取得の代表的手段

2.1.1 文字列長プロパティ/関数

多くの言語やライブラリは、文字列の長さを返すプロパティや関数を提供する。ただしその戻り値がどの単位かは一様ではない。ある環境では「内部配列の要素数」(符号化単位)を返し、別の環境では「文字単位の数」を返す場合がある。利用者仕様書で戻り値の単位を確認し、期待する意味(バイト、コードポイント、表示単位など)に一致しているかを確かめる必要がある。

2.1.1.1 例:文字列の種類ごとの挙動差

言語によっては、文字列を複数の種類に分けて扱うことがある。たとえばUTF-16ベースの文字列型では「サロゲートを含む場合の扱い」が問題になり、UTF-32ベースではコードポイント数と一致しやすい、などの差が出る。さらに、同じ言語でも「生のバイト列」と「テキスト文字列」を別型として提供していることがあり、その場合の長さ関数は別の概念を返す。結果として、型の違いだけで数値が変わるため、設計段階で対象となる文字列型を固定することが望ましい。

2.2 文字の結合(合成文字)と長さのズレ

結合文字は、複数のコードポイントが組になって一つの表示単位に見えるケースを作る。代表例としては、基底文字に結合用マークが付くことで見た目が変化する組合せがある。コードポイント数を長さとすると、ユーザーが数える感覚より長く見えることがある。一方で表示単位(グラフェム)を基準にすると、カーソル操作や「1文字入力」のような体験と整合しやすい。よって「長さ」を境界条件として使う用途では、どの種のズレが許容されるかを決める必要がある。

2.3 サロゲートやエスケープの影響

UTF-16のような符号化方式では、コードポイントのうち一部がサロゲートペアとして表現される。そのため符号化単位(16ビット要素)を長さとして返す実装では、コードポイント数より大きな値が出る可能性がある。加えて、エスケープ表現(たとえばJavaScript文字列の\uXXXXやC系のエスケープ)をソースコード上でどう書くかは、実行時の内部表現に変換されるため、長さの理解を混乱させやすい。重要なのは、計測対象が「ソース表記」なのか「実体化後の文字列」なのかを区別することである。

3 データ処理での利用場面

3.1 入力検証(最大長・最小長)

入力検証では「最大長」をどう定義するかが、ユーザー体験と安全性の両面に影響する。たとえば掲示板投稿や検索条件の上限をバイト長で制限すると、特定の文字コードの利用者で不利になることがある。反対に、コードポイント数で制限すると、見た目の文字数が想定より少ない/多いと感じられることがある。ユーザー向けの制約であればグラフェムクラスタに基づく設計が検討され、内部保存や転送の制約であればバイト長が優先されることが多い。

3.2 画面表示や帳票レイアウト

画面や帳票では、文字列長の概念がさらに「表示幅」と結び付く。全角・半角、フォントの字形、可変幅文字、合字、絵文字などにより、同じ文字数でも占有スペースが異なる。そこで表示上の整形では、文字数ではなくピクセル幅やセル幅、もしくは東アジア幅のような概算規則に基づく計測が使われることがある。結果として、テキスト処理の長さ(コードポイントやバイト)とレイアウト処理の長さ(幅)は別物として扱う設計が現実的になる。

3.3 性能と計算量の考え方

長さ取得の計算コストは実装依存である。内部表現が長さを保持している場合は定数時間で返るが、グラフェム数やコードポイント数を厳密に数える場合は、文字列を走査して境界判定を行う必要があるため線形時間になりやすい。大量データの処理やループ内での頻繁な計測では、どの単位をどの頻度で計算するかが性能に直結する。多くの場面で、先に要件を「十分に近い近似」で満たし、必要な箇所だけ厳密に測るという方針が取られる。

4 関連する概念

4.1 バイト長、コードポイント長、表示幅

バイト長は符号化後の実メモリ・転送量に近い値である。コードポイント長はUnicode上の論理的な文字要素数に関わり、符号化形式が変わっても内容の対応付けを議論しやすい。表示幅はフォントや環境依存の占有量を指し、見た目の整列を目的とする際の主要な指標となる。これらは同じ「長さ」概念に見えても目的と単位が異なるため、用途に応じて使い分ける必要がある。

4.2 トリミングとサブストリング

サブストリングは、どの単位の境界で切り出すかによって結果が変わる。バイト列の単純な切り出しは、可変長符号の場合に不正な中途切断を招く恐れがある。コードポイント境界で切れば論理的な文字の破損を減らせるが、結合マークや複合絵文字が含まれると、ユーザーの認識とずれることがある。トリミング用途では、表示単位の境界での切断、もしくは切断後の表示崩れを抑える処理(末尾の調整など)が検討される。

4.3 正規化と文字列比較の整合性

Unicodeには正規化の考え方があり、見た目が同じでもコードポイント列が異なるケースを扱う枠組みがある。正規化を行わない比較では、等価に見える文字列でも一致判定がずれる可能性がある。長さに関しても、正規化の実施有無でコードポイント数が変化し得るため、比較・格納・長さ制限を行う順序が重要になる。整合性を確保するには、比較の前に正規化規則を定め、制約値がどの単位に対応するかも同時に設計することが求められる。