文字列長計算ツール
文字列を貼り付けると、このツールはその長さを4つの異なる形で報告します。すなわち、JavaScript形式の.length(UTF-16コードユニット)、Unicodeコードポイント、グラフェームクラスター(ユーザーが単一の文字として認識するもの)、およびUTF-8バイト(データベース列に実際に格納されている値)です。エモジコン、フラグ、または組み合わせ記号を含む文字列ではこれらの値が一致せず、このような不一致が多くのバグの原因となっています。
文字列長の4つの意味
-
1
UTF-16コードユニット
`str.length`がJavaScriptで返す値です。ほとんどの文字には1、U+FFFFを超えるすべてのコードポイント(絵文字、古代文字体系など)には2を返します。
-
2
コードポイント
Unicodeスカラー1つにつき1つです。絵文字はそれぞれ1つですが、ZWJシーケンスは複数になります。
-
3
グラフェムクラスター
ユーザーが「1文字」と呼ぶものです。`🇺🇸`は2つのコードポイントですが、1つのグラフェムです。`n̈`も2つのコードポイントですが、1つのグラフェムです。
-
4
UTF-8バイト
DBが保存するデータです。ASCIIは1バイト、標準欧州文字は2バイト、CJKは3バイト、ほとんどの絵文字は4バイトです。
例
| 文字列 | JSの.length | コードポイント | グラフェム | UTF-8バイト |
|---|---|---|---|---|
hello |
5 | 5 | 5 | 5 |
café |
4 | 4 | 4 | 5 |
😀 |
2 | 1 | 1 | 4 |
🇺🇸 |
4 | 2 | 1 | 8 |
👨👩👧(家族) |
8 | 5 | 1 | 18 |
n̈(n + 分音記号) |
2 | 2 | 1 | 3 |
数値が異なる理由
JavaScriptの文字列はUTF-16形式であるため、U+FFFFを超えるコードポイントはサロゲートペア(2つのUTF-16コードユニット)として保存されます。"😀".length === 2となるのはこのためです。ユーザーは😀を1文字として捉えているため、この挙動を嫌います。
グラフェムはさらにその先を行きます。国旗は2つの地域識別子コードポイントで構成されますが、ユーザーはそれを1つの旗として認識します。JavaScriptでは"🇺🇸".length === 4となり、不合理に感じられますが、実際そうなっています。グラフェム単位で反復処理するには、Intl.Segmenter(モダンな手法)やgrapheme-splitterライブラリを使うか、手動で処理します。
UTF-8バイト:データベースが保存する値
型がVARCHAR(255)の列の場合:
- MySQLの
utf8(実体はutf8mb3)では、255はバイト数です。caféは5バイトを消費するため、51個分を格納できます。 - MySQLの
utf8mb4(絵文字も含む本来のUTF-8)でも依然としてバイト数ですが、エンコーディングは4バイトのシーケンスに対応します。 - Postgresの
VARCHAR(255)では、255はバイトではなく文字数(コードポイント)です。 - SQL Serverの
VARCHARでは照合順序(collation)によって異なり、NVARCHARは2バイトのUCS-2単位でカウントします。
データベースのフィールドサイズをユーザーに見える文字数の上限で決める場合は、UTF-8の列では安全を見てバイト数×4を確保してください。各グラフェムはコードポイント1つあたり最大4バイトを消費する可能性があり、ZWJシーケンスではさらに増えます。
Twitter形式の文字数カウント
Twitterはツイートを独自のルールでカウントします。基本はコードポイントですが、絵文字とCJK(中日韓)表意文字はそれぞれ2文字として数えます。100% ASCIIのツイートは280文字まで入力できますが、絵文字を140個使ったツイートは140「文字」が上限になります。
SMSの文字数カウント:GSM 7ビットでは160文字です。GSM以外の文字(á、é、ñ、絵文字)が1つでも含まれるとエンコーディングがUCS-2に切り替わり、メッセージの長さは70文字まで減少します。
実用的な用途
- データベース列のサイズ設定、マイグレーションを書く前にバイト数を確認します。
- APIクォータの適用、ほとんどのAPIは文字数ではなくバイト数をカウントします。
- フォームのバリデーション、ユーザーの感覚に合った正確な文字数(グラフェム)を表示します。
- パフォーマンスのデバッグ、なぜこの正規表現の反復処理が遅いのか? それは、入力がグラフェム単位よりもコードユニット単位で3倍長いからです。
よくある質問
その絵文字は、複数のコードポイントを組み合わせたZWJシーケンスです(例えば家族の絵文字は7つのコードポイントで構成されます)。TwitterはUnicodeの重み付けルールに基づいて2文字としてカウントしますが、エディターは1グラフェムとして表示します。どちらも技術的には正しく、ただ測定している対象が異なるだけです。
UTF-8データベースでは、安全のため想定文字数1文字あたり4バイトを見込んでください。100文字(グラフェム)のフィールドはVARCHAR(400)バイトにすべきです。Postgresのように文字数でカウントするデータベースの場合は、文字セットの設定とあわせてVARCHAR(100)を使います。
JavaScriptでは正規化形式によって異なります。NFCで合成された形(U+00E1)は長さ1ですが、NFDで分解された形(U+0061 + U+0301)は長さ2です。見た目の文字は同じでも、バイト列は異なります。
家族および職業の絵文字は長いZWJシーケンスです。完全なサポートを備えていないフォントでは各コードポイントが個別のグリフとして表示されるため、👨💻は👨+💻に変換されます。OSのフォントをアップグレードすると問題が解決します。
関連ツール
アナグラムジェネレーター
短い語を入力すると、重複した並べ替えを除き、表示件数を調整しながら文字の一意な並べ替えを確認できます。
キャラクター名ジェネレーター
小説、ゲーム、RPGなどのキャラクター名を生成します。ファンタジー、SF、現代から選び、5〜30個の名前を設定すると、すぐに使える名前が手に入ります。
都市名ジェネレーター
世界観づくり、地図、ゲーム、物語、モックデータ向けに、架空の都市、町、村、首都の名前を生成し、各結果に短いメモを添えます。
丸付きテキストジェネレーター
プレーンテキストを丸で囲まれた Unicode 文字に変換します。ソーシャル略歴、チャット、ドキュメントの輪郭、塗りつぶし、丸数字のバリエーション。
カンマから改行へ
カンマ区切りのテキストを1行に1つの項目に変換したり、行をカンマ区切りの文字列にまとめたりできます。
以下記号(≤)
≤ 記号と関連する数学の比較記号をコピーできます。スプレッドシート、論文、ウェブページ向けに Unicode、HTML エンティティ、LaTeX 記法を掲載しています。
このツールは他の言語でも利用できます
- Zeichenlängenrechner [DE]
- Calculadora de Comprimento de String [PT]
- Stränglängdsberäknare [SV]
- Stringlengteberekenaar [NL]
- เครื่องคำนวณความยาวของสตริง [TH]
- Calculateur de longueur de chaîne [FR]
- Calculadora de Longitud de Cadenas [ES]
- Công cụ tính chiều dài chuỗi ký tự [VI]
- Kalkulator Panjang String [ID]
- 문자열 길이 계산기 [KO]
- مقياس طول السلسلة النصية [AR]
- Kalkulator długości ciągu znaków [PL]
- String Length Calculator [EN]
- Calcolatore della lunghezza della stringa [IT]
- Dize Uzunluğu Hesaplayıcı [TR]
- 字符串长度计算器 [ZH]
- Калькулятор длины строки [RU]